gpt4 book ai didi

c# - ASP.NET MVC 3 是否缓存过滤器?

转载 作者:行者123 更新时间:2023-11-30 17:09:12 24 4
gpt4 key购买 nike

我有一个 UnitOfWork 属性,像这样:

public class UnitOfWorkAttribute : ActionFilterAttribute
{
public IDataContext DataContext { get; set; }

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Controller.ViewData.ModelState.IsValid)
{
DataContext.SubmitChanges();
}

base.OnActionExecuted(filterContext);
}
}

如您所见,它具有 DataContext 属性,该属性由 CaSTLe.Windsor 注入(inject)。 DataContext 具有 PerWebRequest 的生活方式 - 意味着为每个请求重用单个实例。

事情是,我不时在这个属性中得到 DataContext is Disposed 异常,我记得 ASP.NET MVC 3 试图以某种方式缓存操作过滤器,所以这可能会导致问题吗?

如果是这样,如何解决问题 - 不使用任何属性并尝试在方法内部使用 ServiceLocator?

是否可以告诉 ASP.NET MVC 在缓存过滤器时不缓存过滤器?

最佳答案

我强烈建议不要使用这样的结构。出于几个原因:

  1. 提交数据上下文不是 Controller (或 Controller 上的修饰属性)的责任。
  2. 这将导致大量重复代码(您将不得不使用此属性修饰大量方法)。
  3. 在执行的那一点(在 OnActionExecuted 方法中)提交数据是否真的安全。

特别是第三点应该引起了你的注意。模型有效这一事实并不意味着可以提交数据上下文的更改。看这个例子:

[UnitOfWorkAttribute]
public View MoveCustomer(int customerId, Address address)
{
try
{
this.customerService.MoveCustomer(customerId, address);
}
catch { }

return View();
}

当然这个例子有点幼稚。你几乎永远不会吞下每一个异常,那将是完全错误的。但它确实表明,当不应保存数据时,操作方法很有可能成功完成。

但除此之外,提交事务真的是 MVC 的问题吗?如果您认为是,您是否仍要用此属性装饰所有操作方法。如果您无需在 Controller 级别执行任何操作而直接实现它,岂不是更好?因为,在此之后您要添加哪些属性?授权属性?记录属性?追踪属性?它停在哪里?

您可以尝试的是对需要在事务中运行的所有业务操作进行建模,以允许您动态添加此行为的方式,而无需更改任何现有代码或在所有地方添加新属性.一种方法是为这些业务操作定义一个接口(interface)。例如:

public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}

使用此接口(interface),您的 Controller 将如下所示:

private readonly ICommandHandler<MoveCustomerCommand> handler;

// constructor
public CustomerController(
ICommandHandler<MoveCustomerCommand> handler)
{
this.handler = handler;
}

public View MoveCustomer(int customerId, Address address)
{
var command = new MoveCustomerCommand
{
CustomerId = customerId,
Address = address,
};

this.handler.Handle(command);

return View();
}

对于系统中的每个业务操作,您定义一个类(DTOParameter Object)。在示例中 MoveCustomerCommand类(class)。此类仅包含数据。该实现定义在一个实现 ICommandHandler<MoveCustomerCommand> 的类中.例如:

public class MoveCustomerCommandHandler
: ICommandHandler<MoveCustomerCommand>
{
private readonly IDataContext context;

public MoveCustomerCommandHandler(IDataContext context)
{
this.context = context;
}

public void Handle(MoveCustomerCommand command)
{
// TODO: Put logic here.
}
}

这看起来像是很多额外的无用代码,但实际上非常有用(如果你仔细观察,它实际上并没有那么多额外的代码)。

有趣的是,您现在可以定义一个装饰器来处理系统中所有命令处理程序的事务:

public class TransactionalCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
private readonly IDataContext context;
private readonly ICommandHandler<TCommand> decoratedHandler;

public TransactionalCommandHandlerDecorator(IDataContext context,
ICommandHandler<TCommand> decoratedHandler)
{
this.context = context;
this.decoratedHandler = decoratedHandler;
}

public void Handle(TCommand command)
{
this.decoratedHandler.Handle(command);

this.context.SubmitChanges();
}
}

这并不比你的 UnitOfWorkAttribute 多多少代码,但不同之处在于,此处理程序可以环绕任何实现并注入(inject)到任何 Controller 中,而 Controller 对此一无所知。执行命令后直接是您真正知道是否可以保存更改的唯一安全位置。

您可以在本文中找到有关这种应用程序设计方式的更多信息:Meanwhile... on the command side of my architecture

关于c# - ASP.NET MVC 3 是否缓存过滤器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13153370/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com