具有依赖注入的实体框架 ObjectContext

发布于 2024-10-10 21:41:16 字数 1075 浏览 6 评论 0原文

好吧,看来我被困在我的应用程序结构中了。这就是我想要做的:

  • UI 层:一个 ASP.NET Webforms 网站。
  • BLL:业务逻辑层,调用 DAL 上的存储库。
  • DAL:.EDMX 文件(实体模型)和带有 Repository 类的 ObjectContext,这些类抽象了每个实体的 CRUD 操作。
  • 实体:POCO 实体。执着无知。由 Microsoft 的 ADO.Net POCO 实体生成器生成。

我想在我的存储库中为每个 HttpContext 创建一个对象上下文,以防止性能/线程[un]安全问题。理想情况下,它会是这样的:

public MyDBEntities ctx
{
    get
    {
        string ocKey = "ctx_" + HttpContext.Current.GetHashCode().ToString("x");
        if (!HttpContext.Current.Items.Contains(ocKey))
            HttpContext.Current.Items.Add(ocKey, new MyDBEntities ());
        return HttpContext.Current.Items[ocKey] as MyDBEntities ;
    }
}  

问题是我不想访问我的 DAL(存储库所在的位置)中的 HttpContext。但我必须以某种方式将 HttpContext 传递给 DAL。根据我的问题此处的答案,我必须使用IoC模式。理想情况下,我想在多层架构中实现类似的东西。

我已经检查过 Autofac,它看起来很有前途。 但是我不确定如何在多层架构中实现这一目标(传递 Httpcontext 以确保每个 HttpContext 实例化一个 ObjectContext)。谁能给我一些关于如何实现这一目标的工作示例?如何在不直接访问DAL中的HttpContext的情况下知道DAL中的HttpContext?我觉得我在设计多层解决方案时有点迷失了。

Well, it seems like I'm stuck in my application structure. Here's what I want to do:

  • UI layer: An ASP.NET webforms website.
  • BLL: Business logic layer which calls the repositories on DAL.
  • DAL: .EDMX file (Entity Model) and ObjectContext with Repository classes which abstract the CRUD operations for each entity.
  • Entities: The POCO Entities. Persistence Ignorant. Generated by Microsoft's ADO.Net POCO Entity Generator.

I'd like to create an obejctcontext per HttpContext in my repositories to prevent performance/thread [un]safety issues. Ideally it would be something like:

public MyDBEntities ctx
{
    get
    {
        string ocKey = "ctx_" + HttpContext.Current.GetHashCode().ToString("x");
        if (!HttpContext.Current.Items.Contains(ocKey))
            HttpContext.Current.Items.Add(ocKey, new MyDBEntities ());
        return HttpContext.Current.Items[ocKey] as MyDBEntities ;
    }
}  

The problem is the I don't want to access HttpContext in my DAL (Where the repositories are located). But I have to somehow pass HttpContext to DAL. based on the answer to my question here, I have to use IoC pattern. Ideally I'd like to achieve something like this in amulti-layered architecture.

I've checked out Autofac and it seems very promising. But I'm not sure how could I achieve this (Passing Httpcontext to make sure one ObjectContext is instantiated per HttpContext) in a multi-layered architecture. Could anyone give me some working example on how to achieve this? How can I be aware of HttpContext in DAL without directly accessing the HttpContext in DAL? I feel like I'm a bit lost in designing a multi-layered solution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

紙鸢 2024-10-17 21:41:16

我从未将 IoC 容器与 WebForms 一起使用,因此将其作为一些高级解决方案,可能应该进一步改进。

您可以尝试将一些 IoC 提供程序创建为单例:

public class IoCProvider
{
  private static IoCProvider _instance = new IoCProvider();

  private IWindsorContainer _container;

  public IWindsorContainer
  {
    get
    {
      return _container;
    }
  }

  public static IoCProvider GetInstance()
  {
    return _instance;
  }

  private IoCProvider()
  {
    _container = new WindsorContainer(new XmlInterpreter(new ConfigResource("castle")));
  }
}

您的 web.config 将必须包含以下部分(该配置基于您的 上一篇文章):

<configuration>
  <configSections>    
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
  </configSections>

  <castle>
    <components>
      <component id="DalLayer"
                 service="MyDal.IDalLayer, MyDal"
                 type="MyDal.MyDalLayer, MyDal"
                 lifestyle="PerWebRequest">
        <!-- 
             Here we define that lifestyle of DalLayer is PerWebRequest so each
             time the container resolves IDalLayer interface in the same Web request
             processing, it returns same instance of DalLayer class
          -->
        <parameters>
          <connectionString>...</connectionString>
        </parameters>
      </component>
      <component id="BusinessLayer"
                 service="MyBll.IBusinessLayer, MyBll"
                 type="MyBll.BusinessLayer, MyBll" />
      <!-- 
           Just example where BusinessLayer receives IDalLayer as
           constructor's parameter.
        -->
    </components>
  </castle>  

  <system.Web>
    ...
  </system.Web>
</configuration>

这些接口和类的实现可能如下所示:

public IDalLayer
{
  IRepository<T> GetRepository<T>();  // Simplified solution with generic repository
  Commint(); // Unit of work
}

// DalLayer holds Object context. Bacause of PerWebRequest lifestyle you can 
// resolve this class several time during request processing and you will still
// get same instance = single ObjectContext.
public class DalLayer : IDalLayer, IDisposable
{
  private ObjectContext _context; // use context when creating repositories

  public DalLayer(string connectionString) { ... }

  ...
}

public interface IBusinessLayer
{
  // Each service implementation will receive necessary 
  // repositories from constructor. 
  // BusinessLayer will pass them when creating service
  // instance

  // Some business service exposing methods for UI layer
  ISomeService SomeService { get; } 
}

public class BusinessLayer : IBusinessLayer
{
  private IDalLayer _dalLayer;

  public BusinessLayer(IDalLayer dalLayer) { ... }

  ...
}

您可以为页面定义基类并公开业务层(您可以对任何其他可以解析的类执行相同的操作):

public abstract class MyBaseForm : Page
{
  private IBusinessLayer _businessLayer = null;
  protected IBusinessLayer BusinessLayer
  {
    get 
    { 
      if (_businessLayer == null)
      {
        _businessLayer = IoCProvider.GetInstance().Container.Resolve<IBusinessLayer>(); 
      }

      return _businessLayer;         
  }

  ...
}

复杂的解决方案涉及使用自定义 PageHandlerFactory 直接解析页面并注入依赖项。如果您想使用此类解决方案,请检查 Spring.NET 框架(另一个带有 IoC 容器的 API)。

I have never used IoC container with WebForms so get this as some high level solution which should probably be futher improved.

You can try creating some IoC provider as singleton:

public class IoCProvider
{
  private static IoCProvider _instance = new IoCProvider();

  private IWindsorContainer _container;

  public IWindsorContainer
  {
    get
    {
      return _container;
    }
  }

  public static IoCProvider GetInstance()
  {
    return _instance;
  }

  private IoCProvider()
  {
    _container = new WindsorContainer(new XmlInterpreter(new ConfigResource("castle")));
  }
}

Your web.config will have to contain sections like (the configuration is based on your previous post):

<configuration>
  <configSections>    
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
  </configSections>

  <castle>
    <components>
      <component id="DalLayer"
                 service="MyDal.IDalLayer, MyDal"
                 type="MyDal.MyDalLayer, MyDal"
                 lifestyle="PerWebRequest">
        <!-- 
             Here we define that lifestyle of DalLayer is PerWebRequest so each
             time the container resolves IDalLayer interface in the same Web request
             processing, it returns same instance of DalLayer class
          -->
        <parameters>
          <connectionString>...</connectionString>
        </parameters>
      </component>
      <component id="BusinessLayer"
                 service="MyBll.IBusinessLayer, MyBll"
                 type="MyBll.BusinessLayer, MyBll" />
      <!-- 
           Just example where BusinessLayer receives IDalLayer as
           constructor's parameter.
        -->
    </components>
  </castle>  

  <system.Web>
    ...
  </system.Web>
</configuration>

Implementation of these interfaces and classes can look like:

public IDalLayer
{
  IRepository<T> GetRepository<T>();  // Simplified solution with generic repository
  Commint(); // Unit of work
}

// DalLayer holds Object context. Bacause of PerWebRequest lifestyle you can 
// resolve this class several time during request processing and you will still
// get same instance = single ObjectContext.
public class DalLayer : IDalLayer, IDisposable
{
  private ObjectContext _context; // use context when creating repositories

  public DalLayer(string connectionString) { ... }

  ...
}

public interface IBusinessLayer
{
  // Each service implementation will receive necessary 
  // repositories from constructor. 
  // BusinessLayer will pass them when creating service
  // instance

  // Some business service exposing methods for UI layer
  ISomeService SomeService { get; } 
}

public class BusinessLayer : IBusinessLayer
{
  private IDalLayer _dalLayer;

  public BusinessLayer(IDalLayer dalLayer) { ... }

  ...
}

Than you can define base class for your pages and expose the business layer (you can do the same with any other class which can be resolved):

public abstract class MyBaseForm : Page
{
  private IBusinessLayer _businessLayer = null;
  protected IBusinessLayer BusinessLayer
  {
    get 
    { 
      if (_businessLayer == null)
      {
        _businessLayer = IoCProvider.GetInstance().Container.Resolve<IBusinessLayer>(); 
      }

      return _businessLayer;         
  }

  ...
}

Complex solution whould involve using custom PageHandlerFactory to resolve pages directly and inject dependencies. If you want to use such solution check Spring.NET framework (another API with IoC container).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文