LoginSignup
0
0

More than 5 years have passed since last update.

WindowsアプリにOWINホストWEBアプリをオンしてみた

Last updated at Posted at 2014-11-14

WebフレームワークにはNancyを使いました。

※SignalRが含まれていますがまだ手を付けていません。

プロジェクト構成

FormとWebページが混在しています。分けたいです。

20141112_proj_tree.png

package.config

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="jQuery" version="1.6.4" targetFramework="net451" />
  <package id="jquery.TypeScript.DefinitelyTyped" version="1.4.0" targetFramework="net451" />
  <package id="Microsoft.AspNet.Razor" version="2.0.30506.0" targetFramework="net451" />
  <package id="Microsoft.AspNet.SignalR" version="2.1.2" targetFramework="net451" />
  <package id="Microsoft.AspNet.SignalR.Core" version="2.1.2" targetFramework="net451" />
  <package id="Microsoft.AspNet.SignalR.JS" version="2.1.2" targetFramework="net451" />
  <package id="Microsoft.AspNet.SignalR.SystemWeb" version="2.1.2" targetFramework="net451" />
  <package id="Microsoft.Owin" version="3.0.0" targetFramework="net451" />
  <package id="Microsoft.Owin.Host.HttpListener" version="3.0.0" targetFramework="net451" />
  <package id="Microsoft.Owin.Host.SystemWeb" version="2.0.1" targetFramework="net451" />
  <package id="Microsoft.Owin.Hosting" version="3.0.0" targetFramework="net451" />
  <package id="Microsoft.Owin.Security" version="3.0.0" targetFramework="net451" />
  <package id="Nancy" version="0.23.2" targetFramework="net451" />
  <package id="Nancy.Authentication.Forms" version="0.23.2" targetFramework="net451" />
  <package id="Nancy.Owin" version="0.23.2" targetFramework="net451" />
  <package id="Nancy.Viewengines.Razor" version="0.23.2" targetFramework="net451" />
  <package id="Newtonsoft.Json" version="6.0.4" targetFramework="net451" />
  <package id="Owin" version="1.0" targetFramework="net451" />
</packages>

Bootstrapperクラス

Windowsアプリでホストする都合上、RootPathProviderを独自に用意する必要があります。

今回はデバッグビルドの出力先が bin\Debug に生成されていることを前提とした、SelfHostRootProviderクラスを実装しました。 (リリースビルドのときはexeとリソースフォルダが同じ場所に配置されると思うので、気にしていません。)

あとは、静的リソース場所の設定とフォーム認証とセッションの有効化を行っています。

namespace SelfHostApp2
{
    public class MyBootstrapper : DefaultNancyBootstrapper
    {
        protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
        {
            base.ApplicationStartup(container, pipelines);
#if DEBUG
            container.Register<IRootPathProvider>(new SelfHostRootProvider());
#endif

            CookieBasedSessions.Enable(pipelines);
        }

        protected override void ConfigureConventions(NancyConventions nancyConventions)
        {
            base.ConfigureConventions(nancyConventions);

            this.Conventions.StaticContentsConventions.Clear();
            this.Conventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("/Content"));
            this.Conventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("/Scripts"));
        }

        protected override void ConfigureRequestContainer(Nancy.TinyIoc.TinyIoCContainer container, NancyContext context)
        {
            base.ConfigureRequestContainer(container, context);

            container.Register<IUserMapper, UserDatabase>(); //今回は掲載していないが、認証用のUserDatabaseクラスが別途存在する。
        }

        protected override void RequestStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines, NancyContext context)
        {
            base.RequestStartup(container, pipelines, context);


            var formsAuthConfiguration = new FormsAuthenticationConfiguration()
            {
                RedirectUrl = "/Auth", //認証失敗時のリダイレクト先
                UserMapper = container.Resolve<IUserMapper>()
            };
            FormsAuthentication.Enable(pipelines, formsAuthConfiguration);  //フォーム認証の有効化
        }
    }

#if DEBUG
    public class SelfHostRootProvider : IRootPathProvider
    {
        public string GetRootPath()
        {
            var assembly = Assembly.GetEntryAssembly();

            return assembly != null ?
                GetProjectDirectory(assembly.Location) :
                GetProjectDirectory(Assembly.GetExecutingAssembly().Location);
        }

        private string GetProjectDirectory(string asmPath)
        {
            var di = new DirectoryInfo(Path.GetDirectoryName(asmPath));
            return di.Parent.Parent.FullName;
        }
    }
#endif
}

Razorテンプレート

Razorテンプレートからhtmlが生成され、静的リソースの参照が可能ことを確認しました。

ここに載せてはいませんが、フォーム認証機能とセッション機能も有効に動きました。

@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<dynamic>

<!DOCTYPE html>

<html lang="jp" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>@Model.Detail</title>
    <link rel="stylesheet" href="/Content/style/index.css" />
</head>
<body>
    <div class="container">
        <p>24時間まえの時間は @DateTime.Now.AddHours(-24.0d) です。</p>
        <p>現在の時間は @DateTime.Now です。</p>
        <p>24時間後の時間は @DateTime.Now.AddHours(24.0d) です。</p>
        <img class="fax-image" src="/Content/img/faxfax.jpg" />
    </div>
    <script src="/Scripts/jquery-1.6.4.min.js"></script>
    <script src="/Scripts/Hoge.js"></script>
</body>
</html>

TypeScript

プロジェクトがWindowsアプリケーションのため、TypeScriptファイルを編集保存してもjavascriptへの自動変換は行われません。

Webアプリケーションのプロジェクトファイルと比較して差異を確認したところ、下記2箇所を追加することで自動変換されるようになりました。

1. /Project 要素

以下のImport要素を追加。

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.Default.props" Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.Default.props')" />

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets" Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets')" /> 

2. /Project/PropertyGroup 要素

先頭のPropertyGroup要素に以下を追加。

<TypeScriptToolsVersion>1.0</TypeScriptToolsVersion> 

フォーム

using Microsoft.Owin.Hosting;

namespace SelfHostApp
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            btnStart.Enabled = true;
            btnStop.Enabled = false;
        }

        private IDisposable webapp = null;

        private void button1_Click(object sender, EventArgs e)
        {
            var url = "http://+:" + txtPort.Text;
            this.webapp = WebApp.Start(url);
            btnStart.Enabled = false;
            btnStop.Enabled = true;
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            StopWebApp();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            StopWebApp();
            btnStart.Enabled = true;
            btnStop.Enabled = false;
        }

        private void StopWebApp()
        {
            if (webapp != null)
                webapp.Dispose();
        }
    }
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0