我该如何正确地使用统一到ConnectionString的传递给我的信息库类? [英] How do I correctly use Unity to pass a ConnectionString to my repository classes?

查看:320
本文介绍了我该如何正确地使用统一到ConnectionString的传递给我的信息库类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从字面上刚刚开始使用Unity应用程序块的依赖注入库来自微软,和我来脱胶。

这是我的IoC类会处理我的具体类的实例其接口类型(所以我不必我想在我的控制器的存储库,每次保持所谓的解决IoC容器上):

 公共类的IoC
{
    公共静态无效Intialise(UnityConfigurationSection节,字符串的connectionString)
    {
        _connectionString =的connectionString;
        _container =新UnityContainer();
        section.Configure(_container);
    }    私有静态IUnityContainer _container;
    私人静态字符串_connectionString;    公共静态IMovementRepository MovementRepository
    {
        {返回_container.Resolve< IMovementRepository>(); }
    }
}

那么,这个想法是,从我的控制,我可以做到以下几点:

  _repository = IoC.MovementRepository;

我目前得到的错误:


  

例外是:
  出现InvalidOperationException - 类型
  字符串不能建造。你必须
  配置容器供应这
  值。


现在,我猜想这是因为我的映射的具体执行要求其构造一个字符串参数。具体类如下:

 公共密封类MovementRepository:仓库,IMovementRepository
{
    公共MovementRepository(字符串的connectionString):基地(的connectionString){}
}

:从继承

 公共抽象类库
{
    公共库(字符串的connectionString)
    {
        _connectionString =的connectionString;
    }    公共虚拟字符串的ConnectionString
    {
        {返回_connectionString; }
    }
    私人只读字符串_connectionString;
}

现在,我在这方面采取了正确的方法是什么?我不应该在我的具体实现松耦合类型的构造?即我应该删除的构造,只是让ConnectionString属性确定get / set这样我就可以做到以下几点:

 公共静态IMovementRepository MovementRepository
{
   得到
   {
      返回_container.Resolve< IMovementRepository>(
         新ParameterOverrides
         {
            {
               的ConnectionString,_connectionString
            }
         } .OnType&所述; IMovementRepository>());
   }
}

所以,我基本上希望知道如何让我的连接字符串,以我的相匹配的国际奥委会规则和保持我的控制器和具体的仓库松耦合这样我就可以在日后方便地更改数据源的正确方法具体类型。

修改09:52:

只是再次重申我后。我想知道传递的ConnectionString或IRepositoryConfiguration对象(preFER这个想法,由于MC),从团结的具体类的正确方法。我不是什么我传球,我只是如何传递,同时保持松耦合太大惊小怪。


解决方案

可能是最直接的方式做到这一点是建立一个构造部分的统一配置和构造单元的内部映射的类型有一个参数元素对于传入你已经在你的web配置的connectionStrings节中定义的连接字符串名称值的连接字符串。

在你的构造code存储库类,有一个使用的连接字符串的名称值来从connectionStrings节的完整的连接字符串一些code。

编辑:

下面是你使用Unity 2.0为例

在你的web.config中,指定连接字符串和团结映射一个映射的 IRepository< T> SqlRepository< T> 。根据您的其他问题,我们假设 IRepository< T> 是在你的样板工程和 SqlRepository< T> 在你的DAL项目。

 <?XML版本=1.0&GT?;
<结构>
    < configSections>
        <节名称=团结TYPE =Microsoft.P​​ractices.Unity.Configuration.UnityConfigurationSection,Microsoft.P​​ractices.Unity.Configuration/>
    < / configSections>
    <&是connectionStrings GT;
        <添加名称=的SqlConnection的connectionString =数据源=(本地)\\ SQLEX $ P $干燥综合征;集成安全性= SSPI;初始目录=数据库名;的providerName =System.Data.SqlClient的/>
    < /&是connectionStrings GT;
    <统一>
        <集装箱>
            <集装箱>
                <各类>
                    <类型type =ModelProject.IRepository`1,ModelProjectmapTo =DALProject.SqlRepository`1,DALProject>
                        <&构造GT;
                            < PARAM NAME =的connectionString>
                                <值值=的SqlConnection/>
                            < /参数>
                        < /构造>
                    < /类型>
                < /类型>
            < /容器>
        < /箱>
  < /统一性GT;
< /结构>

现在的 IRepository< T> 中的样板工程接口。在这个例子中,我也将使用LINQ to SQL的返回从SQL数据库对象

 命名空间ModelProject
{
    ///<总结>
    ///由库实现的接口返回
    ///<见CREF =IQueryable`T/>对象的集合
    ///< /总结>
    ///< typeparam NAME =T>对象类型返回< / typeparam>
    公共接口IRepository< T>
    {
        IQueryable的< T>项目{搞定; }
    }
}

以及 SQLRepository< T> 类的DAL项目

 命名空间DALProject
{
    ///<总结>
    ///用于返回一个&LT通用类;见CREF =IQueryable`T/>
    ///类型集合
    ///< /总结>
    ///< typeparam NAME =T>对象类型< / typeparam>
    公共类SqlRepository< T> :IRepository< T>其中T:类
    {
        私人表< T> _表;        公共SqlRepository(字符串的connectionString)
        {
            //使用ConnectionString参数值来获得
            //从在&lt连接字符串;是connectionStrings>部分
            //在web.config中
            字符串连接= ConfigurationManager.ConnectionStrings [的connectionString] .ConnectionString;            _table =(新的DataContext(连接)) - 的GetTable LT; T>();
        }        ///<总结>
        ///获取一个<见CREF =IQueryable`T/>对象的集合
        ///< /总结>
        公众的IQueryable< T>项目
        {
            {返回_table; }
        }
    }
}

我们还使用自定义控制器工厂,以便统一返回控制器我们。通过这种方式,统一将注入任何依赖该控制器具有

在Global.asax中

 命名空间WebApplicationProject
{
    公共类MvcApplication:System.Web.HttpApplication
    {
        公共静态无效的RegisterRoutes(RouteCollection路线)
        {
            //你的路由
        }        保护无效的Application_Start()
        {
            的RegisterRoutes(RouteTable.Routes);
            ControllerBuilder.Current.SetControllerFactory(新UnityControllerFactory());
        }
    }    公共类UnityControllerFactory:DefaultControllerFactory
    {
        私人IUnityContainer _container;        公共UnityControllerFactory()
        {
            _container =新UnityContainer();            VAR controllerTypes从t =在Assembly.GetExecutingAssembly()。GetTypes()
                                  其中,typeof运算(一个IController).IsAssignableFrom(T)
                                  选择吨;            的foreach(在controllerTypes T型)
                _container.RegisterType(T,t.FullName);            UnityConfigurationSection部分=(UnityConfigurationSection)ConfigurationManager.GetSection(团结);            section.Configure(_container);
        }        保护覆盖一个IController GetControllerInstance(RequestContext的RequestContext的,类型controllerType)
        {
            //看http://stackoverflow.com/questions/1357485/asp-net-mvc2-$p$pview-1-are-there-any-breaking-changes/1601706#1601706
            如果(controllerType == NULL){返回NULL; }            回报(一个IController)_container.Resolve(controllerType);
        }
    }}

和这里有一个控制器的例子。 每页可能在基控制器或控制器作为属性定义的。

 命名空间WebApplicationProject.Controllers
{
    公共类CustomersController:控制器
    {
        私人IRepository<客户> _customerRepository;
        公众诠释每页{搞定;组; }        公共CustomersController(){}        公共CustomersController(IRepository<客户> customerRepository)
        {
            this._customerRepository = customerRepository;
            //让我们将它设置为每页10个项目。
            this.PageSize = 10;
        }        公众的ViewResult列表(字符串customerType,诠释页)
        {
            VAR customerByType =(customerType == NULL)?
                customerRepository.Items:customerRepository.Items.Where(X => x.CustomerType == customerType);            INT totalCustomers = customerByType.Count();
            计算机[总页数] =(INT)Math.Ceiling((双)totalCustomers /每页);
            计算机[当前页] =页;
            计算机[CustomerType] = customerType;            //从集合得到正确的客户
            //根据页码和客户类型。
            返回查看(customerByType
                .Skip((页 - 1)*每页)
                。取(每页)
                .ToList()
            );
        }    }
}

当调用客户名单控制器动作,团结会正确实例化 SqlRepository&LT的实例;客户> 控制器和注入构造这一点。 T> 设置在统一配置,并传递到构造函数的输入 SqlRepository< T> SqlRepository&LT ConnectionString中的字符串C $ C>。

I've literally just started using the Unity Application Blocks Dependency Injection library from Microsoft, and I've come unstuck.

This is my IoC class that'll handle the instantiation of my concrete classes to their interface types (so I don't have to keep called Resolve on the IoC container each time I want a repository in my controller):

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>(); }
    }
}

So, the idea is that from my Controller, I can just do the following:

_repository = IoC.MovementRepository;

I am currently getting the error:

Exception is: InvalidOperationException - The type String cannot be constructed. You must configure the container to supply this value.

Now, I'm assuming this is because my mapped concrete implementation requires a single string parameter for its constructor. The concrete class is as follows:

public sealed class MovementRepository : Repository, IMovementRepository
{
    public MovementRepository(string connectionString) : base(connectionString) { }
}

Which inherits from:

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

    public virtual string ConnectionString
    {
        get { return _connectionString; }
    }
    private readonly string _connectionString;
}

Now, am I doing this the correct way? Should I not have a constructor in my concrete implementation of a loosely coupled type? I.e. should I remove the constructor and just make the ConnectionString property a Get/Set so I can do the following:

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

So, I basically wish to know how to get my connection string to my concrete type in the correct way that matches the IoC rules and keeps my Controller and concrete repositories loosely coupled so I can easily change the DataSource at a later date.

EDIT 09:52:

Just to re-iterate what I'm after. I want to know the correct way to pass the ConnectionString or an IRepositoryConfiguration object (prefer that idea, thanks Mc) to a concrete class from Unity. I'm not too fussed on what I pass, just how I pass it whilst maintaining loose coupling.

解决方案

Probably the most straight forward way to do this is to set up a constructor section for your mapped type in the unity configuration and inside the constructor section have a parameter element for the connection string that passes in a name value for a connection string you have defined in the connectionStrings section of your web configuration.

Inside your constructor code for the Repository class, have some code that uses the name value of the connection string to get the full connection string from the connectionStrings section.

EDIT:

Here's an example for you using Unity 2.0

In your web.config, specify the connection string and a mapping for unity to map an IRepository<T> to a SqlRepository<T>. Based on your other questions, we'll assume that IRepository<T> is in your model project and SqlRepository<T> is in your DAL project.

<?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>

Now for the IRepository<T> interface in the model project. In this example, I'm also going to be using LINQ to SQL to return objects from the SQL Database

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; }
    }
}

And the SQLRepository<T> class in the DAL project

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; }
        }
    }
}

Let's also use a custom controller factory to allow unity to return controllers for us. This way, unity will inject any dependencies that the controllers have

In 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);
        }
    }

}

And Here's a controller example. PageSize might be defined on a base controller or on the controller as a property.

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()
            );
        }

    }
}

When the customers list controller action is invoked, unity will correctly instantiate an instance of SqlRepository<Customer> for the controller and inject this into the constructor. the connectionString string used for SqlRepository<T> is set in the unity configuration and is passed into the constructor for a typed SqlRepository<T>.

这篇关于我该如何正确地使用统一到ConnectionString的传递给我的信息库类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆