WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

OleDb + JET 用のパラメータ

by WebSurfer 16. May 2021 12:39

ADO.NET + JET (または ACE) + OleDb プロバイダで Access を操作する場合、この記事の一番下に書いたサンプルコードのように SQL 文に用いるパラメータには疑問符 (?) で指定される位置パラメータマーカーを使用することになっています。そこを名前付きパラメータを使ったらどうなるかという話を書きます。

実行結果1

エラーになると思っていたのですが、そうはならず少なくとも見かけは期待通り動いている例がみられたので、ちょっと調べてみた次第です。

Microsoft のドキュメント「パラメーターおよびパラメーターのデータ型の構成 (ADO.NET)」に概略が書いてありますが、SQL 文をパラメータ化する場合、パラメータのプレースホルダーの構文はデータソースとプロバイダに依存するそうです。

ADO.NET で Access を操作する際、プロバイダには .NET Framework Data Provider for OLE DB を利用するのが普通と思います。

その場合、SQL 文には疑問符 (?) で指定される位置パラメータマーカーを使用するということになっています。Microsoft のドキュメント OleDbCommand.Parameters Property(日本語版は翻訳がアレです)に以下のように書いてあります。

"Remarks: The OLE DB .NET Provider does not support named parameters for passing parameters to an SQL statement or a stored procedure called by an OleDbCommand when CommandType is set to Text. In this case, the question mark (?) placeholder must be used."

"must" は書いてあることが仕様の絶対的要件であることを意味するそうです。

それに反して名前付きパラメータを使ったらどうなるか試してみました。下のコードの INSERT 文で、...VALUES (?, ?) のところを ...VALUES (Info1, Info2) に変えてみます。実行結果は上の画像と同様に問題なしでした。

しかし、...VALUES (Info, Info) とか ...VALUES (a, a) というように同じ名前を使うと、[Info1], [Info2] には最初のパラメータ(下のコード例では "Info1" と名付けた方)に代入した値のみしか INSERT されないという不可解な動きになります。その結果が下の画像です。

実行結果2

個人的には、疑問符 (?) が must ならそれに反することをしたら即エラーにするのが良いと思うのですがどうでしょう? エラーも出さないで不可解な結果になって、それに気が付かないということもあるでしょうから。

以下にこの記事を書くのに使った .NET Framework 4.8 のコンソールアプリのサンプルコードを載せておきます。

using System;
using System.Data.OleDb;

namespace ConsoleAccess
{
    class Program
    {
        static void Main(string[] args)
        {
            var path = @"C:\Users\surfe\...\Access.mdb";
            var connString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + path;
            var sqlInsert = "INSERT INTO [XXX] ([Info1], [Info2]) VALUES (?, ?)";

            using (var connection = new OleDbConnection(connString))
            {
                connection.Open();
                using (var command = new OleDbCommand())
                {
                    command.Connection = connection;
                    command.CommandType = System.Data.CommandType.Text;
                    command.CommandText = sqlInsert;
                    
                    // パラメータ名を付けるのは以下のような使い方をする場合必要
                    command.Parameters.Add(new OleDbParameter("Info1", OleDbType.Char));
                    command.Parameters.Add(new OleDbParameter("Info2", OleDbType.Char));
                    
                    // コードの並び順を変えても名前で指定したパラメータに代入される
                    command.Parameters["Info2"].Value = "info2";
                    command.Parameters["Info1"].Value = "info1";

                    var i = command.ExecuteNonQuery();

                    Console.WriteLine($"Affected Rows: {i}");
                }

                int id = -1;
                using (var command = new OleDbCommand("SELECT @@IDENTITY", connection))
                {
                    object obj = command.ExecuteScalar();
                    if (obj != null && obj.GetType() != typeof(DBNull))
                    {
                        id = (int)obj;
                    }
                    Console.WriteLine($"New id: {id}");
                }

                var sqlSelect = "SELECT [ID], [Info1], [Info2] FROM [XXX] WHERE ID = ?";
                using (var command = new OleDbCommand())
                {
                    command.Connection = connection;
                    command.CommandType = System.Data.CommandType.Text;
                    command.CommandText = sqlSelect;

                    command.Parameters.Add(new OleDbParameter("ID", OleDbType.Integer));
                    command.Parameters["ID"].Value = id;

                    using (var reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            Console.WriteLine($"ID: {reader[0]}, " +
                                $"Info1: { reader[1]}, Info2; {reader[2]} ");
                        }
                    }
                }
            }
        }
    }
}

Tags: , ,

ADO.NET

カスタム Html ヘルパーで IUrlHelper を利用 (CORE)

by WebSurfer 17. April 2021 12:27

先の記事「カスタム Tag ヘルパーで IUrlHelper を利用 (CORE)」のカスタム html ヘルパー版です。加えて、比較のために、同等な機能を部分ビューで実装する方法も書いてみました。

カスタム Html ヘルパー

カスタム html ヘルパーは ASP.NET Core MVC では推奨されてないのか、Microsoft のドキュメントには作成方法の記事が見当たりませんでした。でも、使うことは可能なようですので、先の記事と同じく内部で IUrlHelper を利用する html ヘルパーを書いてみました。

.NET Framework 版の MVC5 アプリでは、カスタム html ヘルパーの中で以下のコードのようにして UrlHelper オブジェクトを取得できます。

using System.Web;
using System.Web.Mvc;

namespace Mvc5App.HtmlHelpers
{
    public static class Mvc5AppHelpers
    {
        public static IHtmlString AchorTag(this HtmlHelper helper,
                                           string contoller, 
                                           string action, 
                                           string text)
        {
            var urlHepler = new UrlHelper(helper.ViewContext.RequestContext);
            var path = urlHepler.Action(action, contoller);

            return MvcHtmlString.Create(
                $"<a href=\"{path}\">{HttpUtility.HtmlEncode(text)}</a>");
        }
    }
}

Core 3.1 / 5.0 版の MVC アプリでは、先の記事「カスタム Tag ヘルパーで IUrlHelper を利用 (CORE)」に書きましたように、ASP.NET Core 組み込みの DI 機能を利用してコンストラクタ経由で IUrlHelperFactory と IActionContextAccessor を DI し、IUrlHelperFactory の GetUrlHelper(ActionContext) メソッドを使っ�� IUrlHelper オブジェクトを取得しました。・・・よく調べてみると、LinkGenerator API を取得して利用する方が良さそうです。LinkGenerator を使ったカスタム html ヘルパーは下の「2021/4/18 追記」に書きます。

しかし、カスタム html ヘルパーで上のコード例のように拡張メソッドを使う場合は、静的クラス内に静的メソッドを配置することになりますので、コンストラクタ経由での DI ができません。

そこをどうするかですが、HttpContextRequestServices プロパティ から IServiceProvider(サービスコンテナーへのアクセスを提供)を取得できますので、それを使って IUrlHelperFactory と IActionContextAccessor のインスタンスを取得できるようです。

HttpContent は IHtmlHelper.ViewContext プロパティから取得できる ViewContext の HttpContext プロパティで取得できます。

それらを利用したカスタム html ヘルパーを書いてみました。以下をコードを見てください。IServiceProvider から IUrlHelperFactory と IActionContextAccessor のインスタンスを取得し、それらを使って IUrlHelper オブジェクトを取得してその Action メソッドにより url パスの文字列を取得しています。(引数の AnchorTagData クラスの定義は先の記事を見てください)

using System;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Web;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using MvcCoreApp.Models;

namespace MvcCoreApp.HtmlHelpers
{
    public static class MvcCoreAppHtmlHelpers
    {
        // 静的クラスなのでコンストラクタ経由での DI はできない。
        // IServiceProvider を取得してそれから IServiceCollection に登録されている
        // IUrlHelperFactory と IActionContextAccessor のインスタンスを取得
        public static IHtmlContent AchorTag(this IHtmlHelper helper,
                                            IEnumerable<AnchorTagData> Info)
        {
            IServiceProvider provider = helper.ViewContext.HttpContext.RequestServices;

            var urlFactory = provider.GetRequiredService<IUrlHelperFactory>();

            var actionAccessor = provider.GetRequiredService<IActionContextAccessor>();

            var urlHelper = urlFactory.GetUrlHelper(actionAccessor.ActionContext);

            var content = "";
            foreach (var data in Info)
            {
                var path = urlHelper.Action(
                    action: data.Action,
                    controller: data.Controller);
                content += "<li class=\"nav-item\">" +
                    $"<a class=\"nav-link text-dark\" href=\"{path}\">" +
                    $"{HttpUtility.HtmlEncode(data.Text)}</a>" +
                    "</li>\r\n";
            }

            var output = $"<ul class=\"navbar-nav flex-grow-1\">{content}</ul>";

            return new HtmlString(output);
        }
    }
}

先のカスタム tag ヘルパーの記事と同様に、startup.cs での IActionContextAccessor のサービスへの登録は必要ですので忘れないようにしてください。具体的なコードは先の記事を見てください。

_Layout.cshtml に、上に定義した html ヘルパーが使えるように using 句を記述し、html ヘルパーに渡すモデルを初期化します。さらに、html ヘルパーを表示する場所に @Html.AchorTag(model) というコードを書きます。以下のような感じ。

@using MvcCoreApp.HtmlHelpers;

@{
    IEnumerable<AnchorTagData> model =
        new List<AnchorTagData> {
            new AnchorTagData { Controller="Home", Action="Index", Text="Home" },
            new AnchorTagData { Controller="Home", Action="Privacy", Text="Privacy" },
            new AnchorTagData { Controller="People", Action="Index", Text="People" },
            new AnchorTagData { Controller="Messages", Action="Index", Text="Messages" },
            new AnchorTagData { Controller="Validation", Action="Create", Text="Validation" },
            new AnchorTagData { Controller="Upload", Action="Index", Text="FileUpload" },
            new AnchorTagData { Controller="Products", Action="Index", Text="Products" },
            new AnchorTagData { Controller="Ajax", Action="Index", Text="Ajax" },
            new AnchorTagData { Controller="IHttpClientFactory", Action="Index", Text="HttpClient" }};
}

// ・・・中略・・・

@Html.AchorTag(model)

// ・・・中略・・・

以上により、_Layout.cshtml に書いた @Html.AchorTag(model) というコードの部分に上の画像の赤枠で示したリンクが表示されます。

部分ビューで実装

次に、先の記事のカスタム tag ヘルパー、この記事のカスタム html ヘルパーと同等の機能を部分ビューを使って実装してみます。

ASP.NET Core の組み込みタグヘルパーのアンカータグヘルパーを以下のように部分ビュー _Navi.cshtml(名前は任意)に組み込みます。

@using MvcCoreApp.Models
@using System.Web;
@model IEnumerable<AnchorTagData>

<ul class="navbar-nav flex-grow-1">
    @foreach (var data in Model)
    {
        <li class="nav-item">
            <a class="nav-link text-dark"
               asp-controller=@data.Controller
               asp-action=@data.Action>
                @HttpUtility.HtmlEncode(data.Text)
            </a>
        </li>
    }
</ul>

上記部分ビューを、部分タグヘルパーを使って、以下のように _Layout.cshtml に配置します。

@{
    IEnumerable<AnchorTagData> model = // 省略 (上と同じ)
}

// ・・・中略・・・

<partial name="_Navi.cshtml" model="model" />

// ・・・中略・・・

これだけで、先の記事のカスタム tag ヘルパー、この記事のカスタム html ヘルパーと同様に、上の画像の赤枠で示したリンクが表示されます。この記事で書いた程度のことを実装するなら部分ビューを使うのが一番シンプルでよさそうだと思いました


-------- 2021/4/18 追記 (LinkGenerator 利用) --------

上のカスタム html ヘルパーのコードは、IUrlHelperFactory と IActionContextAccessor をサービスコンテナーから取得し、 IUrlHelperFactory.GetUrlHelper(ActionContext) メソッドを使って IUrlHelper オブジェクトを取得して利用しています。

しかし、後でよく調べたら、Microsoft のドキュメント「URL 生成の概念」に書いてあるように LinkGenerator API を取得して利用する方が良さそうと思いました。

というわけで、LinkGenerator を使ったカスタム html ヘルパーのコードを以下に書きます。IActionContextAccessor のサービスへの登録は不要ですしコードも簡単になります。LinkGenerator はサービスコンテナに登録済みのようで、以下のようにするだけで取得できます。

using System;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Web;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using MvcCoreApp.Models;

// LinkGenarator の利用
using Microsoft.AspNetCore.Routing;

namespace MvcCoreApp.HtmlHelpers
{
    public static class MvcCoreAppHtmlHelpers
    {
        // 静的クラスなのでコンストラクタ経由での DI はできない。
        // IServiceProvider を取得してそれから IServiceCollection に登録されている
        // LinkGenarator のインスタンスを取得して利用する
        public static IHtmlContent AchorTag(this IHtmlHelper helper,
                                            IEnumerable<AnchorTagData> Info)
        {
            IServiceProvider provider = helper.ViewContext.HttpContext.RequestServices;

            var linkGenerator = provider.GetRequiredService<LinkGenerator>();

            var content = "";
            foreach (var data in Info)
            {
                var path = linkGenerator.GetPathByAction(
                    action: data.Action,
                    controller: data.Controller);
                content += "<li class=\"nav-item\">" +
                    $"<a class=\"nav-link text-dark\" href=\"{path}\">" +
                    $"{HttpUtility.HtmlEncode(data.Text)}</a>" +
                    "</li>\r\n";
            }

            var output = $"<ul class=\"navbar-nav flex-grow-1\">{content}</ul>";

            return new HtmlString(output);
        }
    }
}

Tags: , , ,

CORE

カスタム Tag ヘルパーで IUrlHelper を利用 (CORE)

by WebSurfer 16. April 2021 15:18

ASP.NET Core 3.1 / 5.0 MVC アプリのカスタム Tag ヘルパーで url の文字列を生成したいということがあると思います。そのために IUrlHelper インターフェイスを利用する方法を書きます。(IUrlHelper インターフェイスは .NET Framework 版の MVC5 で使われる UrlHelper クラスに相当します)

カスタム Tag ヘルパー

上の画像の赤枠の部分は、Visual Studio のテンプレートで生成する ASP.NET Core MVC プロジェクトで自動生成される _Layout.cshtml では組み込みのアンカータグヘルパーを並べてリンクを作成していますが、これをカスタム tag ヘルパーを使って表示してみます。

ASP.NET Core MVC でもカスタム html ヘルパーは使えます。ただし、静的クラス / 静的メソッドになるので ASP.NET Core 組み込みのコンストラクタ経由での DI 機能が使えません。そのためか、カスタム html ヘルパーは Core では推奨されてないような感じで、Mocrosoft のドキュメントにも見当たりません。というわけで、この記事ではカスタム html ヘルパーではなくてカスタム tag ヘルパーで実装してみました。

(カスタム html ヘルパーまたは部分ビュー + 組み込み tag ヘルパー使ってもこの記事と同様な機能は実装できます。それらについては別の記事「カスタム Html ヘルパーで IUrlHelper を利用 (CORE)」に書きました。やってみた結果、この記事で書いた機能程度のことを実装するなら部分ビュー + 組み込み tag ヘルパーを使うのが一番シンプルでよさそうだと思いました)

カスタム tag ヘルパーの作成方法の概要は Microsoft のドキュメント「ASP.NET Core のタグ ヘルパー作成」の記事が参考になると思います。

その記事でほとんど用は足りると思いますが、もし、カスタム tag ヘルパー内でコントローラーとアクションメソッドの名前から url パスを作成する必要があると問題です。例えば、以下のようにアクションメソッドに [HttpPost("/fileupload")] というような属性が付与されているような場合、単純に名前から文字列連結で /upload/index というパスを組み立てて a タグに href="/upload/index" と設定したりすると HTTP 404 Not Found となってしまいます。

namespace MvcCoreApp.Controllers
{
    public class UploadController : Controller
    {
        [HttpGet("/fileupload")]
        public IActionResult Index()
        {
            return View();
        }

        // ・・・中略・・・
    }
}

ちなみに、��み込みのアンカータグヘルパーを使って asp-controller="Upload" asp-action="Index" とすると、それから生成される a タグには href="/fileupload" と設定されます。

そのようにならないと困るので、tag ヘルパー内で Url.Action("index", "upload"); というように url ヘルパーを使ってパスを取得したいということになると思います。そのために IUrlHelper オブジェクトを tag ヘルパーのコードの中でどのように取得するかがこの記事の課題です。

.NET Framework 版の MVC5 アプリでは、カスタム html ヘルパーの中で以下のコードのようにして url ヘルパーのオブジェクトを取得できます。

using System.Web;
using System.Web.Mvc;

namespace Mvc5App.HtmlHelpers
{
    public static class Mvc5AppHelpers
    {
        public static IHtmlString AchorTag(this HtmlHelper helper,
                                           string contoller, 
                                           string action, 
                                           string text)
        {
            var urlHepler = new UrlHelper(helper.ViewContext.RequestContext);
            var path = urlHepler.Action(action, contoller);

            return MvcHtmlString.Create(
                $"<a href=\"{path}\">{HttpUtility.HtmlEncode(text)}</a>");
        }
    }
}

Core 版の MVC アプリではもうちょっと頑張ってコードを書かないと url ヘルパーのオブジェクトを取得できません。前置きが長きなってしまいましたが、以下にその方法を書きます。

基本的には、IUrlHelperFactory インターフェイスIUrlHelperFactory.GetUrlHelper(ActionContext) メソッドを使って IUrlHelper オブジェクトを取得することになります。・・・と思いましたが、LinkGenerator API を取得して利用する方が良さそうです。LinkGenerator を使ったカスタム tag ヘルパーは下の「2021/4/18 追記」に書きます。

IUrlHelperFactory は、Visual Studio のテンプレートで作る ASP.NET Core 3.1 / 5.0 MVC アプリのプロジェクトにはデフォルトで IServiceCollection(DI コンテナ)に登録されているようで、tag ヘルパーのコンストラクタ経由で DI できます。

IUrlHelper オブジェクトを生成するためにIUrlHelperFactory.GetUrlHelper(ActionContext) メソッドを使いますが、その引数の「現在の要求に関連付けられている ActionContext」をどのように取得するかが問題でした。調べてみると、IActionContextAccessor を IServiceCollection に登録してコンストラクタ経由で DI できるようにし、その ActionContext プロパティを使うということのようです。

まず、IActionContextAccessor をサービスに登録します。具体的には、startup.cs の ConfigureServices メソッドで以下のようにします。

// 追加
using Microsoft.AspNetCore.Mvc.Infrastructure;

namespace MvcCoreApp
{
    public class Startup
    {

        // ・・・中略・・・

        public void ConfigureServices(IServiceCollection services)
        {
            // 追加
            services.AddSingleton<IActionContextAccessor, 
                                  ActionContextAccessor>();

        // ・・・中略・・・
}

カスタム tag ヘルパーは、Visual Studio のテンプレートで作った ASP.NET Core MVC アプリのプロジェクトのルートに TagHelpers という名前のフォルダを作って実装しました。コードは以下の通りで、コンストラクタ経由で IUrlHelperFactory と IActionContextAccessor が DI されるようにしています。

using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.TagHelpers;
using MvcCoreApp.Models;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using System.Web;

namespace MvcCoreApp.TagHelpers
{
    public class NaviTagHelper : TagHelper
    {
        private readonly IUrlHelperFactory _urlHelperFactory;
        private readonly IActionContextAccessor _actionContextAccessor;

        public NaviTagHelper(IUrlHelperFactory urlHelperFactory,
                             IActionContextAccessor actionContextAccessor)
        {
            _urlHelperFactory = urlHelperFactory;
            _actionContextAccessor = actionContextAccessor;
        }

        public IEnumerable<AnchorTagData> Info { get; set; }

        public override void Process(TagHelperContext context, 
                                     TagHelperOutput output)
        {
            var urlHelper = _urlHelperFactory.GetUrlHelper(
                                _actionContextAccessor.ActionContext);

            output.TagName = "ul";
            var @class = "navbar-nav flex-grow-1";
            output.Attributes.SetAttribute("class", @class);
            var content = "";
            foreach (var data in Info)
            {
                var path = urlHelper.Action(
                    action: data.Action,
                    controller: data.Controller);
                content += "<li class=\"nav-item\">" +
                    $"<a class=\"nav-link text-dark\" href=\"{path}\">" +
                    $"{HttpUtility.HtmlEncode(data.Text)}</a>" +
                    "</li>\r\n";
            }
            output.Content.SetHtmlContent(content);
        }
    }
}

上のカスタム tag ヘルパーで使っているモデル AnchorTagData クラスの定義は以下の通りです。

namespace MvcCoreApp.Models
{
    public class AnchorTagData
    {
        public string Controller { get; set; }
        public string Action { get; set; }
        public string Text { get; set; }
    }

_Layout.cshtml に、上に定義した tag ヘルパーが使えるように addTagHelper ディレクティブを記述し、tag に渡すモデルを初期化します。さらに、tag ヘルパーを表示する場所に <navi info="model"></navi> というタグを配置します。以下のような感じ。

@addTagHelper MvcCoreApp.TagHelpers.NaviTagHelper, MvcCoreApp

@{
    IEnumerable<AnchorTagData> model =
        new List<AnchorTagData> {
            new AnchorTagData { Controller="Home", Action="Index", Text="Home" },
            new AnchorTagData { Controller="Home", Action="Privacy", Text="Privacy" },
            new AnchorTagData { Controller="People", Action="Index", Text="People" },
            new AnchorTagData { Controller="Messages", Action="Index", Text="Messages" },
            new AnchorTagData { Controller="Validation", Action="Create", Text="Validation" },
            new AnchorTagData { Controller="Upload", Action="Index", Text="FileUpload" },
            new AnchorTagData { Controller="Products", Action="Index", Text="Products" },
            new AnchorTagData { Controller="Ajax", Action="Index", Text="Ajax" },
            new AnchorTagData { Controller="IHttpClientFactory", Action="Index", Text="HttpClient" }};
}

// ・・・中略・・・

<navi info="model"></navi>

// ・・・中略・・・

以上により、_Layout.cshtml に配置した <navi info="model"></navi> の部分に、上の画像の赤枠で示したリンクが表示されます。FileUpload へのリンク先も正しく href="/fileupload" となります。


-------- 2021/4/18 追記 (LinkGenerator 利用) --------

上のカスタム tag ヘルパーのコードは、IUrlHelperFactory と IActionContextAccessor を DI により取得し、 IUrlHelperFactory.GetUrlHelper(ActionContext) メソッドを使って IUrlHelper オブジェクトを取得して利用しています。

しかし、後でよく調べたら、Microsoft のドキュメント「URL 生成の概念」に書いてあるように LinkGenerator API を取得して利用する方が良さそうと思いました。

というわけで、LinkGenerator 使ったカスタム tag ヘルパーのコードを以下に書きます。IActionContextAccessor のサービスへの登録は不要ですしコードも簡単になります。LinkGenerator はサービスコンテナに登録済みのようで、以下のように引数に含めるだけで DI できます。

using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.TagHelpers;
using MvcCoreApp.Models;
using System.Web;

// LinkGenarator の利用
using Microsoft.AspNetCore.Routing;

namespace MvcCoreApp.TagHelpers
{
    public class NaviTagHelper : TagHelper
    {
        private readonly LinkGenerator _linkGenerator;

        public NaviTagHelper(LinkGenerator linkGenerator)
        {
            _linkGenerator = linkGenerator;
        }

        public IEnumerable<AnchorTagData> Info { get; set; }

        public override void Process(TagHelperContext context, 
                                     TagHelperOutput output)
        {
            output.TagName = "ul";
            var @class = "navbar-nav flex-grow-1";
            output.Attributes.SetAttribute("class", @class);
            var content = "";
            foreach (var data in Info)
            {
                var path = _linkGenerator.GetPathByAction(
                     action: data.Action,
                     controller: data.Controller);
                content += "<li class=\"nav-item\">" +
                    $"<a class=\"nav-link text-dark\" href=\"{path}\">" +
                    $"{HttpUtility.HtmlEncode(data.Text)}</a>" +
                    "</li>\r\n";
            }
            output.Content.SetHtmlContent(content);
        }
    }
}

Tags: , , ,

CORE

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  September 2021  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

View posts in large calendar