从表面看,对象初始化器似乎对.net 4.0"代码契约"提出了问题,通常在对象构造函数完成时应该建立不变量.然而,据推测,对象初始化器需要在构造完成后设置属性.
我的问题是,"代码契约"的不变量是否能够处理对象初始化器,"好像"属性是在构造函数完成之前设置的?那确实非常好!!
.net design-by-contract .net-4.0 object-initializers code-contracts
我得到了一个具有许多具体类型的程序集,IHandler<TCommand>
如下所示:
public class MoveCustomerHandler : IHandler<MoveCustomerCommand>
{
void IHandler<MoveCustomerCommand>.Handle(MoveCustomerCommand c)
{
// some business logic for moving a customer.
}
}
Run Code Online (Sandbox Code Playgroud)
目前,我正按照以下方式逐一注册:
builder.RegisterType<MoveCustomerHandler>()
.As<IHandler<MoveCustomerCommand>>();
builder.RegisterType<ProcessOrderHandler>()
.As<IHandler<ProcessOrderCommand>>();
builder.RegisterType<SomeOtherFancyHandler>()
.As<IHandler<SomeOtherFancyCommand>>();
// Many handler registrations here...
Run Code Online (Sandbox Code Playgroud)
使用构造函数注入注入命令处理程序,如下所示:
public class OrderController
{
private readonly IHandler<ProcessOrderCommand> handler;
public OrderController(IHandler<ProcessOrderCommand> handler)
{
this.handler = handler;
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法使用Autofac以简单的方式批量注册我的所有处理程序?
我被这个关于(.NET 4.0)协方差和逆向支持Autofac的问题引发了,现在我正试图实现类似的东西,但没有任何运气.
我试图做到的,是在这样的方式配置Autofac,当我解决一个具体的IEventHandler<TEvent>
(使用示范的目的container.Resolve
,但通常的过程中使用构造器注入),Autofac将返回我MultipleDispatchEventHandler<TEvent>
是包装所有注册的事件处理程序,它可分配来自请求的处理程序.
换句话说,当我写这个:
var handler = container
.GetInstance<IEventHandler<CustomerMovedEvent>>();
handler.Handle(new CustomerMovedEvent());
Run Code Online (Sandbox Code Playgroud)
关于应用程序设计(如下所示),我希望MultipleDispatchEventHandler<CustomerMovedEvent>
返回包含a CustomerMovedEventHandler
和a的应用程序NotifyStaffWhenCustomerMovedEventHandler
.
这是应用程序设计:
// Events:
public class CustomerMovedEvent { }
public class CustomerMovedAbroadEvent : CustomerMovedEvent { }
public class SpecialCustomerMovedEvent : CustomerMovedEvent { }
// Event handler definition (note the 'in' keyword):
public interface IEventHandler<in TEvent>
{
void Handle(TEvent e);
}
// Event handler implementations:
public class CustomerMovedEventHandler
: IEventHandler<CustomerMovedEvent>
{
public void Handle(CustomerMovedEvent …
Run Code Online (Sandbox Code Playgroud) 我正在使用我的MVC 4应用程序中的工作单元和通用存储库模式.我试图解决的问题是为我系统中的每个实体创建Repository存根.为了利用Autofac Ioc,我必须为每个实体创建一个存储库类和接口,以便我可以在Autofac中注册它.
应用开始......
builder.RegisterType<SchoolDetailRepository>().As<ISchoolDetailRepository>().InstancePerHttpRequest();
Run Code Online (Sandbox Code Playgroud)
存储库类
public class SchoolDetailRepository : RepositoryBase<SchoolDetail>, ISchoolDetailRepository
{
public SchoolDetailRepository(IDatabaseFactory databaseFactory) : base(databaseFactory)
{
}
}
Run Code Online (Sandbox Code Playgroud)
接口
public interface ISchoolDetailRepository : IRepository<SchoolDetail>
{
}
Run Code Online (Sandbox Code Playgroud)
这似乎是很多额外的工作.
有没有办法注册Type的通用存储库而不是创建所有这些空类?
然后在我的服务类中,我可以通过Ioc将泛型类型传递给构造函数,例如...
public class SchoolService : ISchoolService
{
private readonly IRepository<SchoolDetail> _schoolRepository;
private readonly IUnitOfWork _unitOfWork;
public SchoolService(IRepository<SchoolDetail> schoolRepository, IUnitOfWork unitOfWork)
{
this._schoolRepository = schoolRepository;
this._unitOfWork = unitOfWork;
}
}
Run Code Online (Sandbox Code Playgroud)
容器配置
// Autofac iOC
var builder = new ContainerBuilder();
// register controllers
builder.RegisterControllers(Assembly.GetExecutingAssembly());
// register services
builder.RegisterType<MembershipService>().As<IMembershipService>().InstancePerHttpRequest();
builder.RegisterType<SchoolService>().As<ISchoolService>().InstancePerHttpRequest();
builder.RegisterType<StudentService>().As<IStudentService>().InstancePerHttpRequest();
builder.RegisterType<ClassRoomService>().As<IClassRoomService>().InstancePerHttpRequest(); …
Run Code Online (Sandbox Code Playgroud) 我有一个装饰器,有一些其他依赖项,也应该使用容器解决.例:
public class FooDecorator : IFoo
{
public FooDecorator(IFoo inner, IBar bar, IBaz baz)
}
Run Code Online (Sandbox Code Playgroud)
我可以这样注册:
builder.RegisterType<Foo>().As<IFoo>();
builder.RegisterDecorator<IFoo>((c, inner) =>
new FooDecorator(inner, c.Resolve<IBar>(), c.Resolve<IBaz>()), "key");
Run Code Online (Sandbox Code Playgroud)
这是有效的,但不是很好,我必须手动指定所有其他依赖项.我想做的是:
builder.RegisterDecorator<FooDecorator, IFoo>("key");
Run Code Online (Sandbox Code Playgroud)
将IFoo
其解析为'inner',IFoo
并从容器中解析其他依赖项.这是可能的,还是我可以用Func注册装饰器会导致这种行为?
在ASP.NET Web API(4.0.30506)中似乎有一些奇怪的行为,我以前没见过.
我所看到的是,相同的动作过滤器属性实例在Web API请求上重用.如果此属性将依赖项注入其中,这尤其是一个问题,因为这些依赖项可能特定于Web请求.我知道属性更好是被动的,但我的假设是动作过滤器属性没有被缓存.
我搜索了描述这个的任何文章,博客文章或微软更改日志及其背后的原因,但我找不到一件事.这让我想知道我的配置是否有问题导致这种情况发生.但是,我能够在一个新的,空的Visual Studio 2012 Web API项目中重现这个问题.
我所做的是使用带有"Web API"模板的Visual Studio 2012 ASP.NET MVC 4 Web应用程序项目创建一个新的空项目.它附带了Web API 4.0.20710.0 NuGet包.之后我添加了以下属性:
[DebuggerDisplay("{id}")]
public class TestFilterAttribute : System.Web.Http.Filters.ActionFilterAttribute {
private static readonly List<int> used = new List<int>();
private static int counter;
private readonly int id;
public TestFilterAttribute() {
this.id = Interlocked.Increment(ref counter);
}
public override void OnActionExecuting(HttpActionContext actionContext) {
// Just for testing: I would expect this line never to throw, but it does.
if (used.Contains(this.id)) throw …
Run Code Online (Sandbox Code Playgroud) 我创建了通用接口,假设映射实体以查看模型和向后.我必须在autofac配置中进行大约80次注册.是否可以将它们注册为批次?这是界面:
public interface ICommonMapper<TEntity, TModel, TKey>
where TEntity : BaseEntity<TKey>
where TModel : BaseEntityViewModel<TKey>
where TKey : struct
{
TModel MapEntityToModel(TEntity entity);
TModel MapEntityToModel(TEntity entity, TModel model);
TEntity MapModelToEntity(TModel model);
TEntity MapModelToEntity(TModel model, TEntity entity);
}
Run Code Online (Sandbox Code Playgroud)
谢谢!
这个方法System.Type.GetGenericArguments()
是从.NETStandard 1.0中"丢失"的,我认为它TypeInfo.GenericTypeArguments
是替代品GetGenericArguments()
,但不幸的是,它们在提供开放泛型类型时表现不同.以下面的代码为例:
Type type = typeof(ICommandHandler<>);
type.GetGenericArguments(); // return { TCommand }
type.GetTypeInfo().GenericTypeArguments; // returns empty array
Run Code Online (Sandbox Code Playgroud)
当该GetGenericArguments()
方法返回泛型类型参数时TCommand
,GenericTypeArguments
只返回一个相同的open-generic类型的空数组.
.NET Standard 1.0 的确切行为GenericTypeArguments
和等价物是Type.GetGenericArguments()
什么?
我正在构建一个WinForms应用程序,其UI只包含一个NotifyIcon
动态填充的UI ContextMenuStrip
.有一个MainForm
共同持有的申请,但这是从来没有看见.
我开始尽可能安全地构建它(使用Autofac来处理对象图)并且对我的成功感到非常满意,即使使用O部分也相当不错.随着我目前正在实施的扩展,似乎我发现了我的设计中的一个缺陷,需要重新改造一下; 我想知道我需要去的方式但是有点不清楚如何准确定义依赖关系.
如上所述,菜单部分在启动应用程序后动态填充.为此,我定义了一个IToolStripPopulator
接口:
public interface IToolStripPopulator
{
System.Windows.Forms.ToolStrip PopulateToolStrip(System.Windows.Forms.ToolStrip toolstrip, EventHandler itemclick);
}
Run Code Online (Sandbox Code Playgroud)
将此实现注入到MainForm
,并且Load()
方法PopulateToolStrip()
使用ContextMenuStrip
表单中定义的处理程序调用.populator的依赖关系仅与获取用于菜单项的数据有关.
这个抽象通过一些进化步骤很好地工作,但是当我需要多个事件处理程序时,这已经不够了,例如因为我正在创建几个不同的菜单项组 - 仍然隐藏在单个IToolStripPopulator
界面后面,因为表单不应该是完全关心这一点.
正如我所说,我想我知道一般结构应该是什么样的 - 我将IToolStripPopulator
接口重命名为更具体的东西*并创建了一个新PopulateToolStrip()
方法,其方法不接受EventHandler
参数,而是将其注入到对象中(也允许更多关于实现所需的处理程序数量的更多灵活性等).这样,我的"最重要的" IToolStripPopulator
可以很容易地成为任何数量的特定适配器的适配器.
现在我不清楚的是我应该如何解决EventHandler依赖项.我认为处理程序应该全部定义MainForm
,因为它具有正确响应菜单事件所需的所有其他依赖项,并且它还"拥有"菜单.这意味着我IToolStripPopulator
最终注入到MainForm中的MainForm
对象的依赖关系需要依赖于对象本身Lazy<T>
.
我的第一个想法是定义一个IClickHandlerSource
接口:
public interface IClickHandlerSource
{
EventHandler GetClickHandler();
}
Run Code Online (Sandbox Code Playgroud)
这是由我实现的MainForm
,我的具体IToolStripPopulator
实现依赖于Lazy<IClickHandlerSource>
.虽然这有效,但它是不灵活的.我要么必须为可能越来越多的处理程序定义单独的接口(严重违反OCP与MainForm
类)或不断扩展IClickHandlerSource
(主要违反ISP).直接依赖事件处理程序在消费者方面看起来是一个好主意,但是通过惰性实例(或类似)的属性单独连接构造函数似乎非常混乱 - 如果可能的话.
我最好的打赌似乎是这样的: …
c# dependency-injection inversion-of-control winforms solid-principles
问题的标题重新开始:我在哪里验证命令的授权?
例如,将客户设置为首选包括:
MarkAsPreferred
控制器动作(可以是Winforms或其他);SetCustomerAsPreferredCommand
;SetCustomerAsPreferredCommandHandler
;Customer.MarkAsPreferred()
(域);我确定了3个地方来检查授权:
SomeView.cshtml
if (authorizationService.Authorize("MarkCustomerAsPreferred))
{
// show link
}
Run Code Online (Sandbox Code Playgroud)
CustomerController
[HttpPost]
public ActionResult MarkAsPreferred(Guid id)
{
if (!authorizationService.Authorize("MarkCustomerAsPreferred))
{
return RedirectToAction("Unauthorized");
}
var MarkCustomerAsPreferredCommand { Id = id };
...
}
Run Code Online (Sandbox Code Playgroud)
MarkCustomerAsPreferredCommandHandler
public void Handle(MarkCustomerAsPreferredCommand command)
{
if (!authorizationService.Authorize("MarkCustomerAsPreferred"))
{
throw new Exception("...");
}
customer.MarkAsPreferred();
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:我是否需要在3个地方验证授权,或者我只是过度热心?
我搜索了整个互联网,但没有找到任何关于此的例子或参考.
编辑
经过更多研究和一些测试后,我认为包装命令以添加行为(授权,验证,日志记录),正如Dennis Taub所建议的那样,实施起来更容易,更清晰.
我发现这篇博文正好解释了这个概念.
关于为一个命令设置多个处理程序,我不需要为每个原始命令的每个行为实现一个命令处理程序,一个包装命令可以包装所有处理程序.