3

.NET WebAPI アプリケーションでの DryIoc の使用を調査していて、初期化手順で奇妙な動作に気付きました。簡単なテスト webapi アプリケーションでは、WebApi 構成登録の直後に呼び出される次の DryIoc 登録クラスがあります。

public class DryIocConfig
{
    public static void Register(HttpConfiguration config)
    {
        var c = new Container().WithWebApi(config);

        c.Register<IWidgetService, WidgetService>(Reuse.Singleton);
        c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton);
    }
}

そして、次の WebApi コントローラー:

public class ValuesController : ApiController
{
    private readonly IWidgetService _widgetService;

    public ValuesController(IWidgetService widgetService)
    {
        _widgetService = widgetService;
    }

    // GET api/values
    public IEnumerable<Widget> Get()
    {
        return _widgetService.GetWidgets();
    }
}

これはうまくいくように見えますが、試してみると同じように見えますが、もう少し冗長に書かれたコードではエラーが発生します。

public class DryIocConfig
{
    public static void Register(HttpConfiguration config)
    {
        var c = new Container();
        c.WithWebApi(config);  // Now separate statement rather than chained. 

        c.Register<IWidgetService, WidgetService>(Reuse.Singleton);
        c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton);
    }
}

私が得る例外は次のとおりです(JSONとして):

    {
        "Message" : "An error has occurred.",
        "ExceptionMessage" : "An error occurred when trying to create a controller of type 'ValuesController'. Make sure that the controller has a parameterless public constructor.",
        "ExceptionType" : "System.InvalidOperationException",
        "StackTrace" : "   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n   at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
        "InnerException" : {
            "Message" : "An error has occurred.",
            "ExceptionMessage" : "Type 'IOCContainerTest.DryLoc.Controllers.ValuesController' does not have a default constructor",
            "ExceptionType" : "System.ArgumentException",
            "StackTrace" : "   at System.Linq.Expressions.Expression.New(Type type)\r\n   at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
        }
    }

これは、DryIoc の何かおかしなことですか、それとも、これまで出会ったことのない C# のニュアンスですか?

4

2 に答える 2

1

これはうまくいくようで、うまくいくはずです。明らかに、返されたコンテナーccontainer.WithWebApi(config);は元のコンテナーではありません。これは現時点では予想外であり、少なくともコードのにおいがします。バグが発生する可能性があるからです。いくつかの単体テストを作成し、DryIoC Bitbucket サイトで問題を開くことをお勧めします。

あなたを助けるために、ここにそのようなテストを書く方法のテンプレートがあります。新しいテスト プロジェクトを作成し、次の操作を行います。


NuGet パッケージをインストールする

Install-Package Microsoft.AspNet.WebApi.OwinSelfHost
Install-Package DryIoc.WebApi.Owin.dll
Install-Package Xunit 

コントローラ

public sealed class ValuesController : ApiController
{
    private IWidgetService WidgetService { get; }

    public ValuesController(IWidgetService widgetService)
    {
        if(widgetService == null) 
            throw new ArgumentNullException(nameof(widgetService));
        WidgetService = widgetService;
    }

    [HttpGet]
    public IEnumerable<Widget> Get()
    {
        return WidgetService.GetWidgets().ToArray();
    }
}

OWIN スタートアップ

public sealed class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var config = new HttpConfiguration()
            .ConfigureRouting()
            .ConfigureDependencyInjection();

        app.UseWebApi(config);

        // protip: use OWIN error page instead of ASP.NET yellow pages for better diagnostics 
        // Install-Package Microsoft.Owin.Diagnostics
        // app.UseErrorPage(ErrorPageOptions.ShowAll); 
    }

    private static HttpConfiguration ConfigureRouting(this HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();
        config.Routes.MapHttpRoute(
            name: "default", 
            routeTemplate: "/", 
            defaults: new { controller = "values" });
        return config;
    }

    private static HttpConfiguration ConfigureDependencyInjection(this HttpConfiguration config)
    {
        new Container()
            .Register<IWidgetService, WidgetService>(Reuse.Singleton)
            .Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton)
            .WithWebApi(config);
        return config;
    }
}

単体テスト

[Fact]
public async Task ShouldFoo()
{
    const string baseAddress = "http://localhost:8000";
    using (WebApp.Start<Startup>(baseAddress))
    {
        var httpclient = new HttpClient
        { 
            BaseAddress = new Uri(baseAddress)
        };
        var response = await httpclient.GetAsync("/");
        Assert.That(...);
    }
}
于 2016-04-27T20:54:48.690 に答える