ディーバ Blog

大阪発 C#の会社、株式会社ディーバの Blog です。

Azure Web App で ASP.NET MVC Web アプリの初回アクセスが遅い

ASP.NET MVC Web アプリケーションを Azure Web App へ発行した場合、初回の表示が非常に遅い場合、次の設定を見直すと高速化できます。

常時接続をオン

Azure ポータルで、Web App の「アプリケーション設定」にある「常時接続」をオンにします。

f:id:jz5_diva:20170227140040p:plain

「Web アプリを毎回読み込む必要があることを示します。既定では、Web アプリはアイドルになった後でアンロードされます。この Web アプリで実行されている継続的な Web ジョブがある場合は、このオプションを有効にすることをお勧めします」とのこと。

IIS の開始モード (startMode) 設定の “AlwaysRunning” が、この常時接続 (Always On) にあたるようです。

ファイル発行オプションでプリコンパイルする

Visual Studio の発行の「設定」で、ファイル発行オプションの「発行中にプリコンパイルする」にチェックします。また、「構成」ウィンドウの「プリコンパイル済みサイトを更新可能にする」のチェックを外します。

f:id:jz5_diva:20170227135911p:plain

f:id:jz5_diva:20170227135914p:plain

以上で、発行時に少し時間がかかりますが、初回アクセスの時間が早くなっているはずです。ただし、View のみの更新(cshtml ファイルのみを差し替え)などはできなくなります。

※ 「App_Dataフォルダーのファイルを除外する」は、発行時に App_Data フォルダーの内容を追加や更新したりしません。必要に応じてオン・オフしてください。

発行先の追加ファイルを削除する

プリコンパイルせず発行したことがある場合、プリコンパイルしたアプリの実行に不要なフォルダーがサーバーに残っているため「The directory ‘/App_GlobalResources/’ is not allowed because the application is precompiled」といったエラーが発生するかもしれません。

その場合、ファイル発行オプションの「発行先の追加ファイルを削除する」をチェックして発行すれば、プロジェクトにないファイル等は削除され、エラーが起きません。アプリでサーバーに直接ファイルを作っている場合は、それらのファイルも削除されるので注意してください。

iTextSharp で外字を PDF に出力

少しだけ iTextSharp と日本語外字を扱ったのでメモ。

DirectContent を使う場合

外字ファイルを指定した BaseFont オブジェクトを生成します。DirectContent.ShowTextAligned メソッドを使うと自由な位置にテキストを出力できますが、指定できるフォントがひとつのため外字しか出力できません。

外字ファイル EUDC.TTE をコピーして拡張子を TTF へリネームすると扱えるようです。

TechPress » iTextSharpで外字を利用する方法 を参考にしました。

//using iTextSharp.text;
//using iTextSharp.text.pdf;
//using System;
//using System.IO;
//using System.Linq;
//using System.Text;

private static void Sample1()
{
    var eudcPath = "EUDC.TTF";
    File.Copy(@"c:\Windows\Fonts\EUDC.TTE", eudcPath, true); // 外字ファイルをコピー・リネーム
    var eudcBaseFont = BaseFont.CreateFont(eudcPath, BaseFont.IDENTITY_H, true);

    var doc = new Document();
    var writer = PdfWriter.GetInstance(doc, new FileStream("sample1.pdf", FileMode.Create));
    doc.Open();

    var cb = writer.DirectContent;
    cb.BeginText();
    cb.SetFontAndSize(eudcBaseFont, 12);
    cb.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "外字テキスト", 100, 100, 0);
    cb.EndText();

    doc.Close();
}

Phrase を使う場合

通常のテキストと外字テキストでフォントの指定を変えた Phrase オブジェクトを生成します。

ゆめみるうみそら 夢見海空 » itextSharpで日本語外字の対応 を参考にしました(ほとんどそのままです)。

//using iTextSharp.text;
//using iTextSharp.text.pdf;
//using System;
//using System.IO;
//using System.Linq;
//using System.Text;

private static void Sample2()
{
    var normalFont = new Font(BaseFont.CreateFont(@"c:\Windows\Fonts\msgothic.ttc,0", BaseFont.IDENTITY_H, true), 12, Font.NORMAL, new BaseColor(0, 0, 0));

    var eudcPath = "EUDC.TTF";
    File.Copy(@"c:\Windows\Fonts\EUDC.TTE", eudcPath, true); // 外字ファイルをコピー・リネーム
    var eudcFont = new Font(BaseFont.CreateFont(eudcPath, BaseFont.IDENTITY_H, true), 12, Font.NORMAL, new BaseColor(0, 0, 0));

    var doc = new Document();
    var writer = PdfWriter.GetInstance(doc, new FileStream("sample2.pdf", FileMode.Create));
    doc.Open();

    var p = CreatePhrase("外字を含むテキスト", normalFont, eudcFont);
    doc.Add(p);

    doc.Close();
}

private static Phrase CreatePhrase(string s, Font normalFont, Font eudcFont)
{
    var p = new Phrase();
    foreach (var c in s)
    {
        var buf = Encoding.GetEncoding("Shift_JIS").GetBytes(c.ToString());
        var code = BitConverter.ToUInt16(buf.Reverse().ToArray(), 0);
        var font = (code >= 0xF000 && code <= 0xFFFC) ? eudcFont : normalFont;
        p.Add(new Chunk(c, font));
    }
    return p;
}

フォント フォルダーをエクスプローラーで開く

フォントフォルダー(通常 c:\Windows\Fonts)をエクスプローラーで開くと、特殊な表示になってしまい、実ファイルを参照できません。

ファイルを参照したい場合、パスを \\コンピューター名\c$\Windows\Fonts としてアクセスするテクニックがあるようです。

「Visual Studio 2017 先取り特集」連載の「Visual Studio for Mac」紹介記事が公開されています

2016/2/15、CodeZine で 次期バージョン「Visual Studio 2017(Visual Studio “15")」先取り特集 第3回『使う言語はC#のみ! Macアプリケーションはもちろん、Webアプリやスマホアプリも開発可能な「Visual Studio for Mac」登場』が公開されています。

この第3回は、株式会社ディーバ 代表取締役 青柳臣一が担当しています。

対象読者は次の通り。ご興味のある方はどうぞ。

  • Macでアプリケーション開発をおこなっている方
  • Visual Studioでアプリケーション開発をおこなっていてMacでも開発をおこないたい方
  • Xamarinでの開発をおこなっている方

codezine.jp

PowerShell でディスプレイの解像度を変更

Microsoft スクリプト センター にある Set-ScreenResolution のコードが使えます。2010年に投稿されたものですが、Windows 10 でも動作を確認。

gallery.technet.microsoft.com

コードの内容は、プライマリモニタの解像度を変更します。Win32 API の ChangeDisplaySettings を呼び出しています。使い方は、次の通り。

Set-ScreenResolution -Width 1024 -Height 768       

C# で日本の祝日を取得

C# で日本の祝日を扱います。

f:id:jz5_diva:20170208121003p:plain

取得しない

もっとも簡単で処理的にも速いのは、あらかじめ登録しておくことですよね。常にメンテナンスするような Web サービスであれば、これが一番いいかも。実際、大手グループウェアで数年先のカレンダーを見ると祝日が未設定だったりします。

var holidays = new HashSet<DateTime>()
{
    new DateTime(2017, 1, 1),
    new DateTime(2017, 1, 2),
    new DateTime(2017, 1, 9),
    new DateTime(2017, 2, 11),
    new DateTime(2017, 3, 20),
    new DateTime(2017, 4, 29),
    new DateTime(2017, 5, 3),
    new DateTime(2017, 5, 4),
    new DateTime(2017, 5, 5),
    new DateTime(2017, 7, 17),
    new DateTime(2017, 8, 11),
    new DateTime(2017, 9, 18),
    new DateTime(2017, 9, 23),
    new DateTime(2017, 10, 9),
    new DateTime(2017, 11, 3),
    new DateTime(2017, 11, 23),
    new DateTime(2017, 12, 23),
};

Google カレンダーを利用

でもメンテしたくない、実装も簡単にしたいってことで、Google カレンダーから祝日を得るようにしてみます。Google Calendar API を使って祝日を取る PHP編 - Qiita を参考にして、C# で書いて見ました。

Newtonsoft.Json を利用しています。API については元記事を参照してください。

public static async Task<HashSet<DateTime>> GetHolidaysAsync(int year)
{
    var key = "API_KEY";
    var holidaysId = "japanese__ja@holiday.calendar.google.com";
    var startDate = new DateTime(year, 1, 1).ToString("yyyy-MM-dd") + "T00%3A00%3A00.000Z";
    var endDate = new DateTime(year, 12, 31).ToString("yyyy-MM-dd") + "T00%3A00%3A00.000Z";
    var maxCount = 30;

    var url = $"https://www.googleapis.com/calendar/v3/calendars/{holidaysId}/events?key={key}&timeMin={startDate}&timeMax={endDate}&maxResults={maxCount}&orderBy=startTime&singleEvents=true";
    var client = new WebClient() { Encoding = System.Text.Encoding.UTF8 };
    var json = await client.DownloadStringTaskAsync(url);
    client.Dispose();

    var o = JObject.Parse(json);
    var days = o["items"].Select(i => DateTime.Parse(i["start"]["date"].ToString()));
    return new HashSet<DateTime>(days);
}

次のように使うと最初のコードと同じ結果が得られます。

var holidays = await GetHolidaysAsync(2017);

Excel でシートを別のブックにコピーや移動すると日付が変わる

Excel でシートをコピーや移動すると、日付の値が変わることがあります(!)。

f:id:jz5_diva:20170203182755p:plain

原因は、日付を1900年を基準として扱うか、1904年を基準として扱うかが、ブック間で異なるからです。

Excel のオプション(「ファイル」タブから「オプション」)の「詳細設定」にある「1904年から計算する」の設定を確認してみてください。

f:id:jz5_diva:20170203183143p:plain

参考: Excel の 1900 年を基準とした日付方式と 1904 年を基準とした日付方式の違いについて

C# で国名の一覧を取得・表示する

CultureInfo, RegionInfo を使って国名(台湾・香港なども含む)の一覧を取得します。アプリで国籍の選択などに使えるかなと。

GetCultures でカルチャを取得し、LCID(ロケールID)プロパティを使って RegionInfo を生成します。Name プロパティが2文字のオブジェクトのみ使います。2文字の値は、ISO 3166 の国名コードです。2文字以外の値には “001” (世界)・"029" (カリブ)・"419" (ラテン アメリカ) があります。

var names = CultureInfo
    .GetCultures(CultureTypes.SpecificCultures)
    .Where(c => c.LCID != 4096 /* LOCALE_CUSTOM_UNSPECIFIED を除く */)
    .Select(c => new RegionInfo(c.LCID))
    .Where(r => r.Name.Length == 2)
    .Distinct()
    .OrderBy(r => r.DisplayName)
    .ToDictionary(r => r.Name, r => r.DisplayName);

Windows 10 で実行した結果です。139件ありました。

f:id:jz5_diva:20170120132840p:plain

すべての国が定義されているわけではないようです。CultureInfo.CreateSpecificCulture Method (String) (System.Globalization) の Remarks によると、Windows で定義されている一覧は [MS-LCID]: Appendix A: Product Behavior で参照できます。

参考として Wikipedia の 国の一覧 - Wikipedia では206ヶ国掲載されています。日本政府が承認した国家数は195ヶ国(日本除く)です。

他のサービスの国数も調べてみました。

  • Microsoft アカウントの国/地域は、254個
  • Google アカウントの国/地域は、255個
  • Tiwtter プロフィールの国は、155個と「世界中」