构造函数依赖注入 WebApi 属性

2023-12-09

我一直在寻找 WebApi 属性的非参数注入选项。

我的问题是使用 Structuremap 是否真的可以实现这一点?

我一直在谷歌搜索,但不断提出属性注入(我不喜欢使用)或构造函数注入的假设实现,但迄今为止我无法复制。

我选择的容器是 Structuremap,但是任何这样的例子就足够了,因为我能够转换它。

有人曾经管理过这个吗?


对的,这是可能的。您(像大多数人一样)被 Microsoft 的 Action Filter 属性营销所困扰,这些属性可以方便地放入单个类中,但根本不适合 DI 友好。

解决方案是将 Action Filter 属性分成 2 部分正如这篇文章所示:

  1. 不包含用于标记控制器和操作方法的行为的属性。
  2. 一个 DI 友好的类,它实现了动作过滤器并包含所需的行为。

该方法是使用 IActionFilter 来测试属性是否存在,然后执行所需的行为。可以为操作过滤器提供所有依赖项(通过构造函数),然后在组成应用程序时注入。

IConfigProvider provider = new WebConfigProvider();
IActionFilter filter = new MaxLengthActionFilter(provider);
config.Filters.Add(filter);

NOTE:如果您需要过滤器的任何依赖项的生命周期短于单例,则需要使用GlobalFilterProvider as in 这个答案.

要将其与 StructureMap 连接起来,您需要从 DI 配置模块返回容器的实例。 Application_Start 方法仍然是组合根的一部分,因此您可以在此方法中的任何位置使用容器,并且它仍然不被视为服务定位器模式。请注意,我在这里没有展示完整的 WebApi 设置,因为我假设您已经有了一个可用的 WebApi DI 配置。如果您需要一个,那是另一个问题。

public class DIConfig()
{
    public static IContainer Register()
    {
        // Create the DI container
        var container = new Container();

        // Setup configuration of DI
        container.Configure(r => r.AddRegistry<SomeRegistry>());
        // Add additional registries here...

        #if DEBUG
            container.AssertConfigurationIsValid();
        #endif

        // Return our DI container instance to the composition root
        return container;
    }
}

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        // Hang on to the container instance so you can resolve
        // instances while still in the composition root
        IContainer container = DIConfig.Register();

        AreaRegistration.RegisterAllAreas();

        // Pass the container so we can resolve our IActionFilter
        WebApiConfig.Register(GlobalConfiguration.Configuration, container);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();
    }
}

public static class WebApiConfig
{
    // Add a parameter for IContainer
    public static void Register(HttpConfiguration config, IContainer container)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        // Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable<T> return type.
        // To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries.
        // For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712.
        //config.EnableQuerySupport();

        // Add our action filter
        config.Filters.Add(container.GetInstance<IMaxLengthActionFilter>());
        // Add additional filters here that look for other attributes...
    }
}

MaxLengthActionFilter 的实现看起来像这样:

// Used to uniquely identify the filter in StructureMap
public interface IMaxLengthActionFilter : System.Web.Http.Filters.IActionFilter
{
}

public class MaxLengthActionFitler : IMaxLengthActionFilter
{
    public readonly IConfigProvider configProvider;

    public MaxLengthActionFilter(IConfigProvider configProvider)
    {
        if (configProvider == null)
            throw new ArgumentNullException("configProvider");
        this.configProvider = configProvider;
    }

    public Task<HttpResponseMessage> ExecuteActionFilterAsync(
        HttpActionContext actionContext,
        CancellationToken cancellationToken,
        Func<Task<HttpResponseMessage>> continuation)
    {
        var attribute = this.GetMaxLengthAttribute(filterContext.ActionDescriptor);
        if (attribute != null)
        {
            var maxLength = attribute.MaxLength;
            // Execute your behavior here (before the continuation), 
            // and use the configProvider as needed

            return continuation().ContinueWith(t =>
            {
                // Execute your behavior here (after the continuation), 
                // and use the configProvider as needed

                return t.Result;
            });
        }
        return continuation();
    }

    public bool AllowMultiple
    {
        get { return true; }
    }

    public MaxLengthAttribute GetMaxLengthAttribute(ActionDescriptor actionDescriptor)
    {
        MaxLengthAttribute result = null;

        // Check if the attribute exists on the action method
        result = (MaxLengthAttribute)actionDescriptor
            .GetCustomAttributes(typeof(MaxLengthAttribute), false)
            .SingleOrDefault();

        if (result != null)
        {
            return result;
        }

        // Check if the attribute exists on the controller
        result = (MaxLengthAttribute)actionDescriptor
            .ControllerDescriptor
            .GetCustomAttributes(typeof(MaxLengthAttribute), false)
            .SingleOrDefault();

        return result;
    }
}

还有,你的属性其中不应包含任何行为应该看起来像这样:

// This attribute should contain no behavior. No behavior, nothing needs to be injected.
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class MaxLengthAttribute : Attribute
{
    public MaxLengthAttribute(int maxLength)
    {
        this.MaxLength = maxLength;
    }

    public int MaxLength { get; private set; }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

构造函数依赖注入 WebApi 属性 的相关文章

  • 在 Linux 上用 C 跟踪键盘和鼠标事件

    如何在 Linux 中用 C 语言跟踪键盘或鼠标事件 Like for example if the user presses ESC Shift etc I should be able to track it Same way for
  • C# 中的任意精度小数?

    是否存在任意精度decimal类可用于 C 吗 我见过几个任意精度整数类 但这并不完全相同 您可以使用 J 库java math BigDecimal类 如果已安装 只需添加一个引用即可vjslib me remembers one of
  • BillingClient 始终返回 SERVICE_DISCONNECTED

    所以我有一个计费客户端 我用它实例化 billingClient BillingClient newBuilder this setListener this build 然后我打电话 billingClient startConnecti
  • 对于 Linux 上的 ARM,从 *.hex 转换为 *.bin

    我想使用以下命令将程序上传到我的 STM32F4 Discovery 板st flash命令 问题是当我尝试上传 hex 或 elf 文件时 它不起作用 我尝试了多种方法 例如使用 xxd 从 elf 或 hex 转换为 bin 但当我上传
  • 2 个 kafka 集群的 Spring kafka 消费者

    我在站点 1 3 个代理 处有两个集群设置 cluster 1 在站点 2 3 个代理 处设置 cluster 2 使用spring kafka 1 3 6 消费者 一台机器 通过 KafkaListener注解监听消息 我们如何为每个集群
  • 如何在 python setup.py 中 chmod 文件?

    我使用 setup py 创建了一个 python 包安装 我希望它复制文件夹 为临时创建的 did 中的数据文件 问题是我必须使用 sudo 权限调用 setup py 因为它写入 usr local 因此 当我的数据文件复制到 did
  • 通过 Eloquent 在 laravel 中找到具有相同值的两列?

    我正在开发一个项目 其中有一个表市场 其中有一个 Buyer id 列和一个 seller id 列 当卖家将商品投放市场时 seller id 和 buyer id 相同 这意味着该产品现在正在销售 销售后 buyer id 更改为购买该
  • 使用 Autofac 在特定命名空间中注入依赖项

    我想将 DispatcherNotifiedObservableCollection 作为 ObservableCollection 注入 且仅注入 所有 ViewModel 位于 MyProject ViewModels 中 有了 Nin
  • Microsoft Build Tools 2013 缺少 v120 目录

    我们已经安装了 Microsoft Build Tools 2013 从http www microsoft com en us download details aspx id 40760 http www microsoft com e
  • MySQL:进行基本搜索

    我的数据库中有一个名称表 我希望对其进行模糊搜索 例如我的数据库包含 Name ID John Smith 1 Edward Smith 2 Gabriel Gray 3 Paul Roberts 4 目前 当我通过 python 搜索数据
  • hibernate中映射到数据库表的bean的默认继承策略是什么?

    这是我在 stackoverflow 中的第一个查询 我想我正在提供所有必要的输入 我已经提供了我的 Java bean 和数据库表详细信息如下 Java Bean 类 import java sql Timestamp import ja
  • 如何启用和访问笔记本和 IPython 内核的调试日志记录

    我正在对 IPython 内核进行一项小型研究 并尝试从中获取调试日志并查看它如何与笔记本交互 现在看起来我的发行版中附带的文档和示例配置已经完全过时了 问题 ipython 内核日志文件位于哪里 如何在 jupyter 笔记本和 ipyt
  • 如何将 gradle 项目转换为 android 项目

    我使用 Eclipse ADT 并且通过配置 gt 转换为 gradle 项目将我的 android 项目转换为 gradle 项目 实际上我需要将我的 gradle 项目转换为 android 项目 我怎样才能做到这一点 Eclipse
  • Android 上的推送器

    我正在尝试让 Pusher 在 Android 上运行 这是我的需求 必须支持 私人 频道 必须支持安全连接 必须能够覆盖推送器 身份验证端点 注意 我已经尝试过以下路线 在 WebView 中加载 Pusher js 并让它回退到 Soc
  • 异常中的错误代码与异常层次结构

    您认为在异常中使用错误代码来指定错误类型可以吗 请看一下这段代码 public class MyException extends Exception public static final String ERROR CODE INVALI
  • 在 AWS ec2 实例上使用“sudo pip”时出现错误

    我正在尝试在 aws ec2 实例上运行一个小型 python 代码 需要 pytz 和其他一些包 当我尝试安装 pytz 时 出现一些错误 ec2 user ip 172 31 28 178 pip install pytz Collec
  • Guava Splitter/Joiners 每次使用时都应该创建吗?

    Guava 包含用于拆分和连接字符串的实用程序 但它需要实例化 Splitter Joiner 对象才能执行此操作 这些是小对象 通常仅包含要分割 合并的字符 维护对这些对象的引用以便重用它们是一个好主意 还是在需要它们时创建它们并让它们被
  • 如何在shell中获取clock_gettime(2)时钟?

    我看不到这样的选项date proc uptime是基于引导的 而不是单调的 最后我发现cat proc timer list grep now产生的纳秒数是通过以下方式获得的ktime get如果我理解正确的话 它会返回单调时间 但这非常
  • Twitter iOS 个人资料页面配置

    我正在尝试构建一个类似于 Twitter 个人资料页面的页面 看起来他们正在使用基本的UITableView 最上面的配置文件就是tableHeaderView 这些选项卡是UISegmentedControl在SectionRowHead
  • 使用 Microsoft OneDrive API/SDK 的客户端分页

    我正在尝试使用 Microsoft OneDrive API SDK 实现客户端分页 为此 我需要将项目总数作为来自 API 的响应 并根据传递给 API 的跳过和最大限制值 应获取响应 In the 列出项目 https develope

随机推荐