如何正确使用Unity将ConnectionString传递给我的存储库类?
我刚刚开始使用微软的Unity应用程序块dependency injection库,而且我已经解开了。
这是我的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(); } } }
所以,我的想法是,从我的控制器,我可以做到以下几点:
_repository = IoC.MovementRepository;
我目前收到错误:
exception是:InvalidOperationException – 无法构造String类型。 您必须配置容器以提供此值。
现在,我假设这是因为我的映射具体实现需要为其构造函数提供单个字符串参数。 具体课程如下:
public sealed class MovementRepository : Repository, IMovementRepository { public MovementRepository(string connectionString) : base(connectionString) { } }
其中inheritance自:
public abstract class Repository { public Repository(string connectionString) { _connectionString = connectionString; } public virtual string ConnectionString { get { return _connectionString; } } private readonly string _connectionString; }
现在,我这样做是正确的吗? 我是否应该在松散耦合类型的具体实现中没有构造函数? 即我应该删除构造函数,只是使ConnectionString属性为Get / Set,以便我可以执行以下操作:
public static IMovementRepository MovementRepository { get { return _container.Resolve( new ParameterOverrides { { "ConnectionString", _connectionString } }.OnType() ); } }
所以,我基本上希望知道如何以符合IoC规则的正确方式将我的连接字符串连接到我的具体类型,并保持我的Controller和具体存储库松散耦合,以便我可以在以后轻松更改DataSource。
编辑09:52:
只是重复我想要的东西。 我想知道将ConnectionString或IRepositoryConfiguration对象(更喜欢这个想法,感谢Mc)传递给Unity的具体类的正确方法。 我对通过的内容并不太感兴趣,只是在保持松耦合的同时如何通过它。
可能最直接的方法是在unity配置中为映射类型设置构造函数部分,在构造函数部分内部有一个连接字符串的参数元素,该元素传递一个已定义的连接字符串的名称值在Web配置的connectionStrings部分中。
在Repository类的构造函数代码中,有一些代码使用连接字符串的名称值来从connectionStrings部分获取完整的连接字符串。
编辑:
以下是使用Unity 2.0的示例
在web.config中,指定连接字符串和unity的映射,以将IRepository
映射到SqlRepository
。 根据您的其他问题,我们假设IRepository
在您的模型项目中,而SqlRepository
在您的DAL项目中。
现在为模型项目中的IRepository
接口。 在这个例子中,我还将使用LINQ to SQL从SQL数据库返回对象
namespace ModelProject { /// /// Interface implemented by a Repository to return /// collections of objects /// /// Object type to return public interface IRepository { IQueryable Items { get; } } }
和DAL项目中的SQLRepository
类
namespace DALProject { /// /// Generic class for returning an /// collection of types /// /// object type public class SqlRepository : IRepository where T : class { private Table _table; public SqlRepository(string connectionString) { // use the connectionString argument value to get the // connection string from the section // in web.config string connection = ConfigurationManager.ConnectionStrings[connectionString].ConnectionString; _table = (new DataContext(connection)).GetTable(); } /// /// Gets an collection of objects /// public IQueryable Items { get { return _table; } } } }
我们还使用自定义控制器工厂,让我们为我们返回控制器。 这样,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); } } }
这是一个控制器示例。 PageSize
可以作为属性在基本控制器或控制器上定义。
namespace WebApplicationProject.Controllers { public class CustomersController : Controller { private IRepository _customerRepository; public int PageSize { get; set; } public CustomersController() { } public CustomersController(IRepository 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() ); } } }
当调用客户列表控制器操作时,unity将正确地为控制器实例化SqlRepository
的实例并将其注入构造函数。 用于SqlRepository
的connectionString字符串在unity配置中设置,并传递给类型化SqlRepository
的构造函数。
您可以为此配置统一容器:
IUnityContainer container = new UnityContainer() .RegisterType( new InjectionConstructor("connectionstring goes here"));
在XLM中可能是这样的:
或者将连接字符串包装为mcaaltuntas指出。
我没有使用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将解析您的配置对象。 您也可以轻松地在此方法中添加额外的参数。
更新
我认为在您的具体类(抽象存储库和MovementRepository)中有一个接受IRepositoryConfiguration对象的构造函数是可以的。 因为它们是实现细节和IMovementRepository的具体实现。所以他们需要知道连接字符串。
Setter或Constructor Injection
我更喜欢构造函数注入而不是setter注入。 我认为构造函数注入会导致更多可发现的API。 在想要实例化对象时,在构造函数注入中,您会看到对象需要工作的内容,但在Setter注入中,您必须了解要设置哪个属性以使用API。 有关详细信息,您可以阅读Constructor ve Setter Injection
我会添加另一种方式:)
您可以使用在注册类型时传递给构造函数的注入参数。 这样你仍然可以使用构造函数注入。
class Repository : IRepository { readonly string m_ConnectionString; public Repository(string connectionString) { ConnectionString = connectionString; } } //When registering container.RegisterType(new InjectionConstructor("connectionstring"));