C# 如何正确使用Unity将ConnectionString传递到存储库类?

C# 如何正确使用Unity将ConnectionString传递到存储库类?,c#,dependency-injection,inversion-of-control,unity-container,repository-pattern,C#,Dependency Injection,Inversion Of Control,Unity Container,Repository Pattern,实际上,我刚刚开始使用微软的Unity应用程序块依赖注入库,但我没有成功 这是我的IoC类,它将把我的具体类实例化为它们的接口类型(因此,每当我希望在控制器中有一个存储库时,我不必在IoC容器上保持调用Resolve): 我当前收到错误信息: 例外情况是: InvalidOperationException-类型 无法构造字符串。你必须 配置容器以提供此 价值观 现在,我假设这是因为映射的具体实现需要一个字符串参数作为其构造函数。混凝土等级如下: public sealed class Move

实际上,我刚刚开始使用微软的Unity应用程序块依赖注入库,但我没有成功

这是我的IoC类,它将把我的具体类实例化为它们的接口类型(因此,每当我希望在控制器中有一个存储库时,我不必在IoC容器上保持调用Resolve):

我当前收到错误信息:

例外情况是: InvalidOperationException-类型 无法构造字符串。你必须 配置容器以提供此 价值观

现在,我假设这是因为映射的具体实现需要一个字符串参数作为其构造函数。混凝土等级如下:

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

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

    public virtual string ConnectionString
    {
        get { return _connectionString; }
    }
    private readonly string _connectionString;
}
现在,我这样做对吗?在松散耦合类型的具体实现中不应该有构造函数吗?也就是说,我是否应该删除构造函数并将ConnectionString属性设置为Get/Set,以便执行以下操作:

_repository = IoC.MovementRepository;
public static IMovementRepository MovementRepository
{
   get
   {
      return _container.Resolve<IMovementRepository>(
         new ParameterOverrides
         {
            { 
               "ConnectionString", _connectionString 
            }
         }.OnType<IMovementRepository>() );
   }
}
公共静态IMovementRepository移动存储库
{
得到
{
return\u container.Resolve(
新参数覆盖
{
{ 
“连接字符串”\u连接字符串
}
}.OnType());
}
}
因此,我基本上希望知道如何以符合IoC规则的正确方式将连接字符串连接到具体类型,并保持控制器和具体存储库的松散耦合,以便以后可以轻松地更改数据源

编辑09:52:


只是重复一下我想要的。我想知道将ConnectionString或IRepositoryConfiguration对象(更喜欢这个想法,谢谢Mc)传递给Unity的具体类的正确方法。我不太在意传递什么,只在乎如何传递,同时保持松散耦合。

我没有使用Unity,但我在这些情况下使用了配置对象。例如,您可以这样编写代码

class Configuration:IRepositoryConfiguration,IMailConfiguration
{
    private string connectionString;

    //IRepository configurations
    public string ConnectionString
    {
        //read connection string from somewhere
        get { return connectionString; }
    }

    //EMail configurations
    public string Smtp
    {
        get { return smpt; }
    }

}

interface IRepositoryConfiguration
{
    string ConnectionString { get;}
}



public abstract class Repository
    {
        public Repository(IRepositoryConfiguration configuration)
        {
            _connectionString = configuration.ConnectionString;
        }

        public virtual string ConnectionString
        {
            get { return _connectionString; }
        }
        private readonly string _connectionString;
    }
因此,您可以注册IRepositoryConfiguration,Unity将解析您的配置对象。此外,您还可以在这种方法中轻松添加额外的参数

更新 我认为在具体类(抽象存储库和移动存储库)中有一个接受IRepositoryConfiguration对象的构造函数是可以的。因为它们是IMovementRepository的实现细节和具体实现,所以它们需要知道连接字符串

Setter或构造函数注入
我更喜欢构造函数注入而不是setter注入。我认为构造函数注入带来了更多可发现的API。在构造函数注入中,当您想要实例化对象时,您会看到对象需要工作什么,但在Setter注入中,您必须了解要设置哪个属性以使用API。有关详细信息,请阅读

,您可以为此配置unity容器:

IUnityContainer container = new UnityContainer()
  .RegisterType<IMovementRepository, MovementRepository>(
    new InjectionConstructor("connectionstring goes here"));
IUnityContainer container=newunitycontainer()
.RegisterType(
新的InjectionConstructor(“connectionstring在这里”);
在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>


或者像McAltuntas指出的那样包装连接字符串。

最直接的方法可能是在unity配置中为映射类型设置一个构造函数部分,并且在构造函数部分中为连接字符串设置一个参数元素,该参数元素为您拥有的连接字符串传入一个名称值在web配置的ConnectionString部分中定义

在存储库类的构造函数代码中,有一些代码使用连接字符串的名称值从ConnectionString部分获取完整的连接字符串

编辑:

下面是一个使用Unity 2.0的示例

在web.config中,为unity指定连接字符串和映射,以将
IRepository
映射到
SqlRepository
。基于您的其他问题,我们将假定
irepositional
在您的模型项目中,
SqlRepository
在您的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>
这里有一个控制器的例子<代码>页面大小可以在基本控制器或控制器上定义为属性

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

    }
}
命名空间WebApplicationProject.Controllers
{
公共类CustomerController:控制器
{
私人电子储蓄(客户储蓄);;
公共int PageSize{get;set;}
公共CustomerController(){}
公共CustomerController(IRepository customerRepository)
{
这是._customerRepository=customerRepository;
//我们将其设置为每页10项。
这个.PageSize=10;
}
公共视图结果列表(字符串customerType,int页)
{
var customerByType=(customerType==null)?
customerRepository.Items:customerRepository.Items.Where(x=>x.CustomerType==CustomerType);
int totalCustomers=customerByType.Count();
ViewData[“TotalPages”]=(int)数学上限((两倍)totalCustomers/PageSize);
ViewData[“当前页面”]=页面;
ViewData[“CustomerType”]=CustomerType;
//从该系列中获得合适的客户
//基于页码和客户类型。
返回视图(customerByType)
.Skip((第1页)*页面大小)
.Take(页面大小)
托利斯先生()
);
}
}
}
调用customers list controller操作时,unity将为控制器正确实例化
SqlRepository
的实例,并将其注入构造函数。用于
SqlRepository
的connectionString字符串在unity配置中设置,并传递到类型化
SqlRepository
的构造函数中

我将添加另一种方式:)

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

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

    }
}
class Repository : IRepository {
  readonly string m_ConnectionString;
  public Repository(string connectionString) {
    ConnectionString = connectionString;
  }
}

//When registering
container.RegisterType<IRepository, Repository>(new InjectionConstructor("connectionstring"));