如何使用 Func 配置依赖注入容器?

2024-01-23

BusinessAction 用于表示用户可以执行的操作。每个操作都与特定实体相关,因此,例如,如果该实体是 Order,则业务操作可以是 CancelOrder、IssueRefund 等。

public abstract class BusinessAction<T>
{
    public Guid Id { get; init; }
    public Func<T, bool> IsEnabledFor { get; init; }
}

public class CancelOrderAction : BusinessAction<Order>
{
    public CancelOrderAction ()
    {
        Id = Guid.Parse("0e07d05c-6298-4c56-87d7-d2ca339fee1e");
        IsEnabledFor = o => o.Status == OrderStatus.Active;
    }
}

然后我需要对与特定类型相关的所有操作进行分组。

public interface IActionRegistry
{
    Task<IEnumerable<Guid>> GetEnabledActionIdsForAsync(Guid entityId);
}

public class ActionRegistry<T> : IActionRegistry
    where T : BaseEntity
{
    private readonly IEnumerable<BusinessAction<T>> _actions;
    private readonly IRepository<T> _repository;

    public ActionRegistry(IEnumerable<BusinessAction<T>> actions, IRepository<T> repository)
    {
        _actions = actions;
        _repository = repository;
    }

    public async Task<IEnumerable<Guid>> GetEnabledActionIdsForAsync(Guid entityId)
    {
        var entity = await _repository.FindByIdAsync(entityId);

        return entity == null
            ? Enumerable.Empty<Guid>()
            : _actions.Where(a => a.IsEnabledFor(entity)).Select(a => a.Id);
    }
}

最后,有一个 API 端点,用于接收实体类型(稍后映射到真实 .NET 类型的一些枚举)和实体 ID。 API端点负责返回为实体的当前状态启用的操作ID。

public class RequestHandler : IRequestHandler<Request, IEnumerable<Guid>>>
{
    private readonly Func<Type, IActionRegistry> _registryFactory;

    public RequestHandler(Func<Type, IActionRegistry> registryFactory)
    {
        _registryFactory = registryFactory;
    }

    public async Task<IEnumerable<Guid>> Handle(Request request, CancellationToken cancellationToken)
    {
        var type = request.EntityType.GetDotnetType();
        var actionRegistry = _registryFactory(type);
        var enabledActions = await actionRegistry.GetEnabledActionIdsForAsync(request.EntityId);

        return enabledActions;
    }
}

问题是:如何在 ASP.NET 中配置依赖注入容器(使用默认选项或 Autofac)以便可以解析 Func

对于参数ActionRegistry<T>我想我可以这样做:

builder.RegisterAssemblyTypes().AsClosedTypesOf(typeof(BusinessAction<>));

builder.RegisterGeneric(typeof(Repository<>))
       .As(typeof(IRepository<>))
       .InstancePerLifetimeScope();

但是,我该如何配置Func<Type, IActionRegistry>这样我就能够自动连接一个请求Order with ActionRegistry<Order>?有没有办法做到这一点,或者我需要通过编写一些基于类型的 switch 语句来手动配置工厂(以及它看起来如何)?

有没有更好的方法来实现我在这里所需要的?最终目标是,一旦我有了运行时类型,我就可以获得与该类型相关的业务操作列表以及存储库(以便我可以从数据库获取实体)。


您尝试做的事情是可能的,但这不是一件常见的事情,也不是您可以开箱即用的神奇事情。您必须编写代码来实现它。

在我开始之前……从未来的角度来看,如果您的重现是这样,您可能会更快地获得帮助并且更多地关注您的问题更加简约。整体BusinessAction<T>并不是真正需要的;这RequestHandler不需要...老实说,您需要重现正在做的事情的是:

public interface IActionRegistry
{
}

public class ActionRegistry<T> : IActionRegistry
{
}

如果其他内容与问题相关,一定要包含它......但在这种情况下,它不是,所以在这里添加它只会使问题更难以阅读和回答。我知道我个人有时会跳过有很多额外内容的问题,因为一天只有这么多小时,你知道吗?

无论如何,以下是您的操作方法,以工作示例的形式:

var builder = new ContainerBuilder();

// Register the action registry generic but not AS the interface.
// You can't register an open generic as a non-generic interface.
builder.RegisterGeneric(typeof(ActionRegistry<>));

// Manually build the factory method. Going from reflection
// System.Type to a generic ActionRegistry<Type> is not common and
// not directly supported.
builder.Register((context, parameters) => {
    // Capture the lifetime scope or you'll get an exception about
    // the resolve operation already being over.
    var scope = context.Resolve<ILifetimeScope>();

    // Here's the factory method. You can add whatever additional
    // enhancements you need, like better error handling.
    return (Type type) => {
        var closedGeneric = typeof(ActionRegistry<>).MakeGenericType(type);
        return scope.Resolve(closedGeneric) as IActionRegistry;
    };
});

var container = builder.Build();

// Now you can resolve it and use it.
var factory = container.Resolve<Func<Type, IActionRegistry>>();
var instance = factory(typeof(DivideByZeroException));
Assert.Equal("ActionRegistry`1", instance.GetType().Name);
Assert.Equal("DivideByZeroException", instance.GetType().GenericTypeArguments[0].Name);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 Func 配置依赖注入容器? 的相关文章

随机推荐

  • 计算减法后剩余多边形的算法

    我有一个大多边形 Pa 多边形内部有很多小 洞 如图 以下是开孔的几个条件 孔不能互相重叠 孔不能超出外多边形 然而 这些洞can触摸多边形的外边 如何高效地获取剩余的多边形 或多边形列表 最简单的方法 蛮力方法 是采取Pa 并通过减去孔逐
  • json.Unmarshal 不返回解码数据[重复]

    这个问题在这里已经有答案了 我在解组从 a 读取的 json 数据时遇到问题 json file type redisConfig struct host string password string func loadRedisConfi
  • 我可以为主键设置ignore_dup_key吗?

    我的表上有一个两列主键 我试图改变它来设置ignore dup key继续使用此命令 ALTER INDEX PK mypk on MyTable SET IGNORE DUP KEY ON 但我收到这个错误 Cannot use inde
  • 循环依赖最佳实践

    我目前正在编写一个网络爬虫 它从互联网上检索信息 简化后看起来像这样 数据访问项目 检索原始数据的对象 将原始数据解析为对象的对象 解析器返回的实体 现在 我正在创建实际的解析器 我将像这样使用它 using Application Dat
  • 为什么我在 Android 设备上无法接收来自 GCM 的消息

    我正在创建一个 android 应用程序 我需要在其中发送 gcm 消息 到目前为止我设法得到设备ID并将其发送到我的服务器 现在 当我尝试将消息从服 务器推送到我的应用程序时 我收到以下消息 multicast id 4987023356
  • EXC_BAD_ACCESS,代码 1,iOS 7.0.x 64 位设备

    我目前正在开发的应用程序在模拟器上完美运行 但自从 Xcode 升级到 5 1 后 我在设备上运行应用程序时遇到问题 如果我在任何 iOS 上的任何非 64 位设备上运行应用程序 它都可以正常运行 但如果我在 64 位设备 iPhone 5
  • 硒页面对象。如何从外部源读取@FindBy定位器?

    我只能在页面对象 FindBy 注释中使用硬编码值 但我想动态解析定位器 public class LoginPage extends BasePage hardocded value works ok FindBy name login
  • 如何正确解析在 ASP.NET Core 3.1 中的ConfigureServices() 中使用的服务?

    我有一个基于 ASP NET Core 3 1 的应用程序 在应用程序启动期间 在ConfigureServices IServiceCollection services 我想注册我的服务 但在配置服务期间 我想根据数据库中找到的设置启动
  • 如何在 Quartz.Net 中让 Job 引发 EventHandler?

    我有一个实例化 Quartz Scheduler 的控制台应用程序 我希望作业能够引发事件处理程序 以便 母应用程序 调用特定的方法 问题是 Job 类似乎与外部类明显是相当隔离的 我确信有一个好方法可以做到这一点 但我还没有偶然发现它 p
  • 如何使用 Visual Studio 2010 从源代码构建 MFC 库

    Visual Studio 历史上始终包含 MFC 库作为源 因此您可以使用提供的 makefile 自行构建它 但在 Visual Studio 2010 中没有 MFC 的 makefile 那么 如何重建它呢 MS 上有文档暗示 ma
  • 使用 jquery 添加和删除 div 的样式属性

    我继承了我正在从事的一个项目 并且正在更新一些 jquery 动画 很少使用 jquery 练习 我有一个 div 需要添加和删除样式属性 这是 div div 在动画中的某个时刻 我需要为其添加一种样式 div 我四处搜寻并找到了 rem
  • 使用 JPL 查询 Prolog 变量

    我想通过JPL进行查询以在java中使用Prolog 我阅读了文档 http www swi prolog org packages jpl java api getting started html prolog 谓词如下 child o
  • 如何避免标题后立即分页

    我有一个 HTML 4 01 CSS 2 1 文档 其中包含一个 H3 标题 后跟一个短 一行 段落块 然后是一个包含多个项目的无序列表 h3 Heading h3 p Some things p ul li Thing one li li
  • PowerShell 和 MS Access 数据库

    我们想使用 PowerShell 创建 AD 用户 使用 CSV 这不是问题 使用脚本就很容易 下一级我们希望使用 PowerShell 和 MS Access 数据库创建 AD 用户 现在我们遇到以下问题 我们可以读取 Access 数据
  • Android 异常 - 来源未知(可能是小部件)

    我有以下 Android 异常 这是由 Bugsense 报告的 我无法找到它来自哪里 因为没有引用我的应用程序的任何类 java lang IndexOutOfBoundsException 无效索引 0 大小为 0 在java util
  • google-maps-sdk-ios - iOS 版 Google 地图 1.4.3 的 arm 7/iphone 5 问题

    我在让我的应用程序引用 iOS 版 Google 地图 1 4 3 sdk 时遇到问题 arm7 和 7s 似乎存在问题 尽管它在模拟器上运行良好 但它拒绝安装到设备 iphone 5 上 我相信我已经遵循了 google 文档中的 API
  • 触发器在两个信号的边沿触发

    我需要一个对两个不同信号的边缘做出反应的触发器 像这样的东西 if rising edge sig1 then bit lt 0 elsif rising edge sig2 then bit lt 1 end if 这样的触发器是否存在或
  • 如何在 SQLAlchemy 中使用子查询来生成移动平均线?

    我的问题是我想检索测量值列表以及这些测量值的移动平均值 我可以使用以下 SQL 语句 postgresql 间隔语法 来做到这一点 SELECT time value SELECT AVG t2 value FROM measurement
  • 如何验证 update_all 是否确实在 Rails 中更新

    鉴于此代码 def create upgrades User update all role upgraded id gt params upgrade redirect to admin upgrades path notice gt S
  • 如何使用 Func 配置依赖注入容器?

    BusinessAction 用于表示用户可以执行的操作 每个操作都与特定实体相关 因此 例如 如果该实体是 Order 则业务操作可以是 CancelOrder IssueRefund 等 public abstract class Bu