如何正确使用Unity将ConnectionString传递给我的存储库类?

djd*_*d87 18 c# dependency-injection inversion-of-control unity-container repository-pattern

我刚刚开始使用微软的Unity应用程序块依赖注入库,而且我已经失败了.

这是我的IoC类,它将处理我的具体类到它们的接口类型的实例化(所以每次我在控制器中需要一个存储库时,我不必在IoC容器上保持名为Resolve):

public class IoC
{
    public static void Intialise(UnityConfigurationSection section, string connectionString)
    {
        _connectionString = connectionString;
        _container = new UnityContainer();
        section.Configure(_container);
    }

    private static IUnityContainer _container;
    private static string _connectionString;

    public static IMovementRepository MovementRepository
    {
        get { return _container.Resolve<IMovementRepository>(); }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,我的想法是,从我的控制器,我可以做到以下几点:

_repository = IoC.MovementRepository;
Run Code Online (Sandbox Code Playgroud)

我目前收到错误:

异常是:InvalidOperationException - 无法构造String类型.您必须配置容器以提供此值.

现在,我假设这是因为我的映射具体实现需要为其构造函数提供单个字符串参数.具体课程如下:

public sealed class MovementRepository : Repository, IMovementRepository
{
    public MovementRepository(string connectionString) : base(connectionString) { }
}
Run Code Online (Sandbox Code Playgroud)

其中继承自:

public abstract class Repository
{
    public Repository(string connectionString)
    {
        _connectionString = connectionString;
    }

    public virtual string ConnectionString
    {
        get { return _connectionString; }
    }
    private readonly string _connectionString;
}
Run Code Online (Sandbox Code Playgroud)

现在,我这样做是正确的吗?我是否应该在松散耦合类型的具体实现中没有构造函数?即我应该删除构造函数,只是使ConnectionString属性为Get/Set,这样我就可以执行以下操作:

public static IMovementRepository MovementRepository
{
   get
   {
      return _container.Resolve<IMovementRepository>(
         new ParameterOverrides
         {
            { 
               "ConnectionString", _connectionString 
            }
         }.OnType<IMovementRepository>() );
   }
}
Run Code Online (Sandbox Code Playgroud)

所以,我基本上希望知道如何以符合IoC规则的正确方式将我的连接字符串连接到我的具体类型,并保持我的Controller和具体存储库松散耦合,以便我可以在以后轻松更改DataSource.

编辑09:52:

只是重复我想要的东西.我想知道将ConnectionString或IRepositoryConfiguration对象(更喜欢这个想法,感谢Mc)传递给Unity的具体类的正确方法.我对通过的内容并不太感兴趣,只是在保持松散耦合的同时如何通过它.

Jan*_*m B 22

您可以为此配置统一容器:

IUnityContainer container = new UnityContainer()
  .RegisterType<IMovementRepository, MovementRepository>(
    new InjectionConstructor("connectionstring goes here"));
Run Code Online (Sandbox Code Playgroud)

在XLM中可能是这样的:

<type type="foo.IMovementRepository,foo" mapTo="foo.MovementRepository,foo">
  <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration">     
   <constructor>
     <param name="connectionString" parameterType="System.String" >
       <value value="conectionstring goes here" type="System.String"/>
     </param>           
   </constructor>
  </typeConfig>
</type>
Run Code Online (Sandbox Code Playgroud)

或者将连接字符串包装为mcaaltuntas指出.


Rus*_*Cam 15

可能最直接的方法是在统一配置中为映射类型设置构造函数部分,在构造函数部分内部有一个连接字符串的参数元素,该元素传递一个已定义的连接字符串的名称值在Web配置的connectionStrings部分中.

在Repository类的构造函数代码中,有一些代码使用连接字符串的名称值来从connectionStrings部分获取完整的连接字符串.

编辑:

以下是使用Unity 2.0的示例

在web.config中,指定连接字符串和unity映射IRepository<T>到a的映射SqlRepository<T>.根据您的其他问题,我们假设IRepository<T>您的模型项目SqlRepository<T>位于您的DAL项目中.

<?xml version="1.0"?>
<configuration>
    <configSections>
        <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
    </configSections>
    <connectionStrings>
        <add name="SqlConnection" connectionString="data source=(local)\SQLEXPRESS;Integrated Security= SSPI; Initial Catalog= DatabaseName;" providerName="System.Data.SqlClient"/>
    </connectionStrings>
    <unity>
        <containers>
            <container>
                <types>
                    <type type="ModelProject.IRepository`1, ModelProject" mapTo="DALProject.SqlRepository`1, DALProject">
                        <constructor>
                            <param name="connectionString">
                                <value value="SqlConnection" />
                            </param>
                        </constructor>
                    </type>
                </types>
            </container>
        </containers>
  </unity>
</configuration>
Run Code Online (Sandbox Code Playgroud)

现在为IRepository<T>模型项目中的接口.在这个例子中,我还将使用LINQ to SQL从SQL数据库返回对象

namespace ModelProject
{
    /// <summary>
    /// Interface implemented by a Repository to return
    /// <see cref="IQueryable`T"/> collections of objects
    /// </summary>
    /// <typeparam name="T">Object type to return</typeparam>
    public interface IRepository<T>
    {
        IQueryable<T> Items { get; }
    }
}
Run Code Online (Sandbox Code Playgroud)

SQLRepository<T>DAL项目中的类

namespace DALProject
{
    /// <summary>
    /// Generic class for returning an <see cref="IQueryable`T"/>
    /// collection of types
    /// </summary>
    /// <typeparam name="T">object type</typeparam>
    public class SqlRepository<T> : IRepository<T> where T : class
    {
        private Table<T> _table;

        public SqlRepository(string connectionString)
        {
            // use the connectionString argument value to get the
            // connection string from the <connectionStrings> section
            // in web.config
            string connection = ConfigurationManager.ConnectionStrings[connectionString].ConnectionString;

            _table = (new DataContext(connection)).GetTable<T>();
        }

        /// <summary>
        /// Gets an <see cref="IQueryable`T"/> collection of objects
        /// </summary>
        public IQueryable<T> Items
        {
            get { return _table; }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我们还使用自定义控制器工厂,让我们为我们返回控制器.这样,unity将注入控制器具有的任何依赖项

在global.asax中

namespace WebApplicationProject
{
    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            // your routes
        }

        protected void Application_Start()
        {
            RegisterRoutes(RouteTable.Routes);
            ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory());
        }
    }

    public class UnityControllerFactory : DefaultControllerFactory
    {
        private IUnityContainer _container;

        public UnityControllerFactory()
        {
            _container = new UnityContainer();

            var controllerTypes = from t in Assembly.GetExecutingAssembly().GetTypes()
                                  where typeof(IController).IsAssignableFrom(t)
                                  select t;

            foreach (Type t in controllerTypes)
                _container.RegisterType(t, t.FullName);

            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");

            section.Configure(_container);
        }

        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            // see http://stackoverflow.com/questions/1357485/asp-net-mvc2-preview-1-are-there-any-breaking-changes/1601706#1601706
            if (controllerType == null) { return null; }

            return (IController)_container.Resolve(controllerType);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

这是一个控制器示例.PageSize可以在基本控制器上或在控制器上定义为属性.

namespace WebApplicationProject.Controllers
{
    public class CustomersController : Controller
    {
        private IRepository<Customer> _customerRepository;
        public int PageSize { get; set; }

        public CustomersController() { }

        public CustomersController(IRepository<Customer> customerRepository)
        {
            this._customerRepository = customerRepository;
            // let's set it to 10 items per page.
            this.PageSize = 10; 
        }

        public ViewResult List(string customerType, int page)
        {
            var customerByType = (customerType == null) ?
                customerRepository.Items : customerRepository.Items.Where(x => x.CustomerType == customerType);

            int totalCustomers = customerByType.Count();
            ViewData["TotalPages"] = (int)Math.Ceiling((double)totalCustomers/ PageSize);
            ViewData["CurrentPage"] = page;
            ViewData["CustomerType"] = customerType;

            // get the right customers from the collection
            // based on page number and customer type.    
            return View(customerByType
                .Skip((page - 1) * PageSize)
                .Take(PageSize)
                .ToList()
            );
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

当调用客户列表控制器操作时,unity将正确地实例化SqlRepository<Customer>控制器的实例并将其注入构造函数.用于的connectionString字符串SqlRepository<T>在unity配置中设置,并传递给类型化的构造函数SqlRepository<T>.