Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我可以将依赖项注入到使用.Net Core WebApi在post方法中创建的模型对象中吗?_C#_.net_Asp.net Core Webapi - Fatal编程技术网

C# 我可以将依赖项注入到使用.Net Core WebApi在post方法中创建的模型对象中吗?

C# 我可以将依赖项注入到使用.Net Core WebApi在post方法中创建的模型对象中吗?,c#,.net,asp.net-core-webapi,C#,.net,Asp.net Core Webapi,如果在我的启动中,我已注册我的依赖项: services.AddScoped<IService, SomeService>(); 我的模型课是这样的 public class Model { ... public Model(IService service) { ... } ... } 如果你想在模型中注入一些东西,你可以选择。在ModelBinder中,您可以使用所有注册的服务访问上下文,并且可以使用所需的任何参数调用模型的构造函数 一般来说,模型不应该引用正在使用它

如果在我的启动中,我已注册我的依赖项:

services.AddScoped<IService, SomeService>();
我的模型课是这样的

public class Model {
...
    public Model(IService service) { ... }
...
}

如果你想在模型中注入一些东西,你可以选择。在ModelBinder中,您可以使用所有注册的服务访问上下文,并且可以使用所需的任何参数调用模型的构造函数

一般来说,模型不应该引用正在使用它们的服务。所以,如果你真的想这样做,请仔细考虑。

你可以为此创建一个。我们可以使用
ComplexTypeModelBinder
作为基础

public class ServiceModelBinder : ComplexTypeModelBinder
{
    public ServiceModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders, ILoggerFactory loggerFactory) 
        : base(propertyBinders, loggerFactory)
    {
    }

    public ServiceModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders, ILoggerFactory loggerFactory, bool allowValidatingTopLevelNodes) : base(propertyBinders, loggerFactory, allowValidatingTopLevelNodes)
    {
    }

    protected override object CreateModel(ModelBindingContext bindingContext)
    {
        var modelTypeInfo = bindingContext.ModelType.GetTypeInfo();

        //if type satisfies default binder requirements just use it
        if (!modelTypeInfo.IsAbstract && modelTypeInfo.GetConstructor(Type.EmptyTypes) != null)
        {
            return base.CreateModel(bindingContext);
        }

        var constructors = modelTypeInfo.GetConstructors();
        if (constructors.Length > 1)
        {
            throw new InvalidOperationException("Model should contain one constructor only");
        }

        var constructor = constructors.First();
        var parameters = constructor.GetParameters();
        //require that all parameters are marked with [FromServices]
        //this step is completely optional
        if (!parameters.Any(p => p.IsDefined(typeof(FromServicesAttribute))))
        {
            throw new InvalidOperationException("Mark all parameters with [FromServices]");
        }

        //build arguments from registered services
        var arguments = parameters
            .Select(p => bindingContext.ActionContext.HttpContext.RequestServices.GetService(p.ParameterType))
            .ToArray();

        return constructor.Invoke(arguments);
    }

}

在领域驱动的设计中,模型不应该使用服务而不是相反的方式吗?具有状态但没有行为的模型将被视为贫血,因此在从JSON反序列化模型之后,下一步将是调用模型上的行为,这可能需要使用服务来完成其操作。这种依赖关系可以注入到模型上的方法中,但如果在模型实例化时这样做,对我来说会更干净。为什么不希望在模型中保留对服务的引用?
public class ServiceModelBinder : ComplexTypeModelBinder
{
    public ServiceModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders, ILoggerFactory loggerFactory) 
        : base(propertyBinders, loggerFactory)
    {
    }

    public ServiceModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders, ILoggerFactory loggerFactory, bool allowValidatingTopLevelNodes) : base(propertyBinders, loggerFactory, allowValidatingTopLevelNodes)
    {
    }

    protected override object CreateModel(ModelBindingContext bindingContext)
    {
        var modelTypeInfo = bindingContext.ModelType.GetTypeInfo();

        //if type satisfies default binder requirements just use it
        if (!modelTypeInfo.IsAbstract && modelTypeInfo.GetConstructor(Type.EmptyTypes) != null)
        {
            return base.CreateModel(bindingContext);
        }

        var constructors = modelTypeInfo.GetConstructors();
        if (constructors.Length > 1)
        {
            throw new InvalidOperationException("Model should contain one constructor only");
        }

        var constructor = constructors.First();
        var parameters = constructor.GetParameters();
        //require that all parameters are marked with [FromServices]
        //this step is completely optional
        if (!parameters.Any(p => p.IsDefined(typeof(FromServicesAttribute))))
        {
            throw new InvalidOperationException("Mark all parameters with [FromServices]");
        }

        //build arguments from registered services
        var arguments = parameters
            .Select(p => bindingContext.ActionContext.HttpContext.RequestServices.GetService(p.ParameterType))
            .ToArray();

        return constructor.Invoke(arguments);
    }

}
public class ServiceModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType)
        {
            var propertyBinders = new Dictionary<ModelMetadata, IModelBinder>();
            for (var i = 0; i < context.Metadata.Properties.Count; i++)
            {
                var property = context.Metadata.Properties[i];
                propertyBinders.Add(property, context.CreateBinder(property));
            }

            var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
            return new ServiceModelBinder(
                propertyBinders,
                loggerFactory,
                allowValidatingTopLevelNodes: true);
        }

        return null;
    }
}
services
    .AddControllersWithViews()
    .AddMvcOptions(options =>
    {
        options.ModelBinderProviders.Insert(0, new ServiceModelBinderProvider());
    })