ぷろじぇくと、みすじら。

Microsoft Edge on iOS Previewがきた

Created at:

どのぐらいの人が待っていたのかわかりませんが(少なくとも自分は待っていた)、Microsoft Edgeのモバイル版が発表されました。今までEdgeを利用していてもGoogle Chromeのようにモバイルで同期できないのが不便でしたがこれで解消されるとうれしいですね。

プレビューテストの登録をしていたら利用できるようになったという通知がTestFlightに来たので試してみました。

レンダリングエンジン

なおレンダリングエンジンはEdgeHTMLを移植したわけではないと解説されています。安心なのか面白くないのか何とも言えないところですね。

プレビュー版(2017/10/06、v2.5)でできること & できないこと

使ってみた感じ

プレビュー版ということで粗削りだったりモッサリなところも多いのですがPCと同期できるようになったのはいいですね。今までできなかったことができるようになるということだけでもよい話なので今後に期待です。

まあ逆に言えばGoogle Chrome for iOSと同様に、同期する必要性が薄いならSafariでいいとも言えます。

スクリーンショット

ペタペタ貼っておきます。

新しいタブを開いたところ。Windows 10と同様によくアクセスするサイト、アドレス&検索ボックス、ニュースフィードが表示される。

アドレスバーの横のマイナスっぽいアイコンを押すとQRコードの読み取り、写真を撮って画像検索、写真を選択して画像検索が可能。

現在開いているタブの一覧ページ(フッターボタンの右から2番目のタブっぽいアイコンで開く)。

履歴が同期されるのでWindows 10側で開いたことのあるページが候補として出てくるっぽい。

画面端からスワイプで戻る。

フッターボタンの真ん中のアイコンをタップでPC(Windows 10 Fall Creators Update以降)に送る、Hand Off的なやつ。ここで端末を選択するとそっちのEdgeで開かれます。

右下のその他機能のメニュー。共有はここに突っ込まれています。

お気に入り同期。よくよく考えたらお気に入りほとんど使ってないのでほとんど入ってなかった…。

設定ページです。

プライバシー設定ページ。

検索エンジンの設定ではGoogleも選べるので安心です。

Browser Platform Status Trackerを.NET Core 2.0に更新した

Created at:

3年ぐらい前からWebブラウザのプラットフォーム機能の開発状況が公開されるようになり、その更新を追いかけて変更内容を一覧するサイトBrowser Platform Status Trackerを公開しています。

最近までASP.NET MVC 5と.NET 4.6で動作していたのですが.NET Coreの機運の高まりを感じたので、.NET Core 2.0 + ASP.NET MVC Core 2.0に移行しました。といっても2か月ぐらい前に一度.NET Core 1.1にして、その後.NET Core 2.0にという感じです。まあそもそもサイトの性質的には動的じゃなくてもいい説もありますがそこは気にせず…。

.NET Core 1.1 + ASP.NET MVC Core化のタイミングで折角なのでHTTPSを有効にして、ドメインもAzureのApp Service(azurewebsites.net)だったので platformstatus.io というドメインへも変更しています。

サイト自体はコンパクトなのでASP.NET Coreへの移行は大した苦労はなかったのですが、やはりRazorテンプレートにヘルパーがなくなった所に関しては既存のASP.NET MVCのアプリを移行する際のハードルになると感じました。数が少ない場合には頑張ってPartialにすればよいのですが、ヘビーに使っている場合には使い勝手も違うので移行不能に近い状態になりそうです。

気づいたこととか

ASP.NET Core 2.0でリバースプロキシの後ろにある場合にスキームを維持したい

Created at:

ASP.NET Core 2.0でアプリケーションがリバースプロキシの後ろにあるケースで、リバースプロキシがHTTPSで受け、アプリにはHTTPで受け渡すような構成というのはよくあるかと思います。

しかしASP.NET Coreは標準のままでは Request.Scheme には"http"が入ることになり、"https"が入っていなくて不都合が…という状況が発生します。

そんな時は大抵のリバースプロキシが送り出すであろう X-Forwarded-* ヘッダーフィールドを反映するミドルウェアがあるのでそれを有効にすることで、リバースプロキシにアクセスされた際の情報を維持できます。

その機能を有効にするには UseForwardedHeaders メソッドでミドルウェアを使用するようにし、その際にどのヘッダーフィールドを使うかを指定します。次の例は上位サーバーからのリクエストの X-Forwareded-Proto (スキーム)を見るようにするという設定です。

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedProto
});

ASP.NET MVC Core 2.0のアプリケーション全体でHTTPSを強制する

Created at:

ASP.NET MVC Core 2.0のアプリケーションでHTTPSを強制するには、RequireHttpsフィルター(RequireHttpsAttributeクラス)をグローバルフィルターに追加することで実現できます。

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services
        .AddMvc(options =>
        {
            options.Filters.Add(new RequireHttpsAttribute());
        });
}

注意点として、RequireHttpsAttributeフィルターはOnAuthorizationメソッド、つまりフィルターパイプラインの一番最初である認可フェーズで処理されるので、ほかの認証/認可フィルターはこのフィルターより後に登録する必要があります。

MicrosoftのサイトにはRewriteエンジンを使う方法も書かれていますが、大抵のケースではフィルターで追加する方法で間に合うと思います。

MVCを使わないASP.NET Coreでもリダイレクトしたい

また、MVCではないASP.NET Coreで同じようなことをしたい場合には以下のようなMiddlewareを書くとよいでしょう(動作未確認)。

public static IApplicationBuilder UseRedirectToHttps(this IApplicationBuilder app)
{
    return app.Use((context, next) =>
    {
        var req = context.Request;
        if (!req.IsHttps)
        {
            var newUrl = new StringBuilder().Append("https://").Append(req.Host.Host).Append(req.PathBase).Append(req.Path).Append(req.QueryString);
            context.Response.Redirect(newUrl.ToString(), permanent: true);
            return Task.CompletedTask;
        }

        return next();
    });
}

IHostingEnvironmentをConfigureServiceで使いたい

ところでグローバルなフィルターを追加するのはいいのですが、環境によっては例えばデバッグ実行時や開発環境では追加したくないということもあります。

Configure メソッド内であれば env.IsProduction() といった感じで切り替えできるのですが、ConfigureService メソッドには IHostingEnvironment が渡ってこないのです。

ではどうするかというと Startup クラスにプロパティやフィールドをはやして、保持しておくという方法で解決できます。まあ Configuration も保持してますしね。

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .AddEnvironmentVariables();
    Configuration = builder.Build();
    HostingEnvironment = env;
}

public IHostingEnvironment HostingEnvironment { get; }

一度保持してしまえば ConfigureServices から参照可能になるので環境ごとに切り替えができます。

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services
        .AddMvc(options =>
        {
            if (HostingEnvironment.IsProduction())
            {
                options.Filters.Add(new RequireHttpsAttribute());
            }
        });
}

ASP.NET MVC Core 2.0が返すJSONをASP.NET Web APIと同様にPascal Caseにしたい

Created at:

ASP.NET MVC CoreのJSONシリアライズではプロパティ名をデフォルトで"camelCase"に変換して吐き出しますが、従来のASP.NET Web APIは"PascalCase"だったので移植する場合などに以前の挙動になってほしいということがあります。

幸いシリアライザの挙動を変更する手段が用意されているのでそこで変更できます。

StartupConfigureServicesでASP.NET MVCを利用するためAddMvcメソッドを呼び出しますが、その際に返ってきたIMvcBuilderAddJsonOptionsを呼び出すことで設定を変更できます。

ContractResolverというプロパティがシリアライズするときに使うリゾルバなのでこれを変更します。従来のASP.NET Web API相当のシリアライザはJSON.NETのデフォルトなのでDefaultContractResolverContractResolverとして設定すれば期待の挙動となります。

services
    .AddMvc()
    .AddJsonOptions(options =>
    {
        options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
    });

他にもJSONのシリアライズをカスタマイズしたい場合にはこの辺りで変更を加えたり、ContractResolverをカスタムしてあげればよいということになります。