C# 在Web API应用程序中,我可以在什么时候截取URI参数并相应地路由调用?
注意:这个问题确实有点类似于,但我想我可以用一种更简单、更具体的方式来回答 我正在使用Castle Windsor拦截传递给我的Web API应用程序的URI,以便向控制器的构造函数注册适当的具体类 我希望能够在URI上传递一个“站点号”,可能总是作为第一个或最后一个参数。看,对于42号场地,而不是C# 在Web API应用程序中,我可以在什么时候截取URI参数并相应地路由调用?,c#,castle-windsor,database-schema,lifecycle,asp.net-web-api-routing,C#,Castle Windsor,Database Schema,Lifecycle,Asp.net Web Api Routing,注意:这个问题确实有点类似于,但我想我可以用一种更简单、更具体的方式来回答 我正在使用Castle Windsor拦截传递给我的Web API应用程序的URI,以便向控制器的构造函数注册适当的具体类 我希望能够在URI上传递一个“站点号”,可能总是作为第一个或最后一个参数。看,对于42号场地,而不是 http://localhost:28642/api/platypi/GetAll ……它将是: http://localhost:28642/api/platypi/42/GetAll -或:
http://localhost:28642/api/platypi/GetAll
……它将是:
http://localhost:28642/api/platypi/42/GetAll
-或:
当我的Web API应用程序第一次“看到”/截取URI时,我想记下该站点编号,以便我可以分配所需的具体存储库,以便Castle Windsor注册。我希望能够做到这一点:
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
if (siteNum == 42)
{
container.Register(
Component.For<IDepartmentRepository>().ImplementedBy<DepartmentRepository42>().LifestylePerWebRequest(),
Component.For<IInventoryItemRepository>().ImplementedBy<InventoryItemRepository42>().LifestylePerWebRequest(),
. . .
}
else if (siteNum = 77)
{
container.Register(
Component.For<IDepartmentRepository>().ImplementedBy<DepartmentRepository77>().LifestylePerWebRequest(),
Component.For<IInventoryItemRepository>().ImplementedBy<InventoryItemRepository77>().LifestylePerWebRequest(),
. . .
}
…成为:
public DepartmentsController(IDepartmentRepository deptsRepository)
{
if (deptsRepository == null)
{
throw new ArgumentNullException("deptsRepository");
}
_deptsRepository = deptsRepository(siteNum);
}
…还是
我仍然有一个问题,在Castle Windsor/控制器获取传入URI之前,我在哪里拦截它,这样我就可以为全局/siteNum变量设置适当的值?我会更改DepartmentRepository()上的构造函数来传递site num,并使用它来获取connectionstring。然后在您的webconfig中为每个站点创建一个connectionstring。您可以使用许多扩展点来实现这一点,我个人使用这个扩展点也可以获得类似的结果 通过扩展
IModelBinder
以下内容创建自定义模型绑定器:
public class SiteManagerModelBinder : IModelBinder
{
#region IModelBinder Members
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.Model != null)
{
throw new InvalidOperationException("Cannot update instances");
}
// Apply your condition to determine if site number is in Url.
if (controllerContext.RouteData.Values['siteNum']!=null)
{
// probably want to resolve this from container just hard coding as example, assumption is that SiteManager, does the repository bits for you.
return new SiteManager((int)controllerContext.RouteData.Values['siteNum']);
}
return null;
}
#endregion
}
public class RepositoryFactorySelector : DefaultTypedFactoryComponentSelector
{
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
return (method.Name.EndsWith("ById") && arguments.Length >= 1 && arguments[0] is int)
? string.Format("Repository{0}", arguments[0])
: base.GetComponentName(method, arguments);
}
}
public class RepositoryInstaller : IWindsorInstaller
{
#region IWindsorInstaller Members
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<Repository>().Configure(c=>c.Named(c.Implementation.Name)));
container.Register(
Component.For<RepositoryFactorySelector, ITypedFactoryComponentSelector>().LifestyleSingleton(),
Component.For<IRepositoryFactory>().AsFactory(c => c.SelectedWith<RepositoryFactorySelector>()));
}
#endregion
}
好的,现在我们需要注册新的ModelBinder:
protected void Application_Start()
{
ModelBinders.Binders.Add(typeof(SiteManager), new SiteManagerModelBinder ());
好的,现在在我们的控制器中,我们所做的就是添加SiteManager作为任何操作的参数,它将由我们的ModelBinder填充
public class DepartmentsController: Controller {
public ActionResult AnyAction(SiteManager siteManager, int whateverElse, ViewModel model)
{
}
}
这里有一种不同的方式,你可以尝试使用温莎城堡,这可能会更好: 创建一个存储库工厂,如下所示:
public interface IRepositoryFactory
{
Repository CreateRepositoryById(int id);
}
创建一个组件选择器,根据以下名称选择正确的存储库:
public class SiteManagerModelBinder : IModelBinder
{
#region IModelBinder Members
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.Model != null)
{
throw new InvalidOperationException("Cannot update instances");
}
// Apply your condition to determine if site number is in Url.
if (controllerContext.RouteData.Values['siteNum']!=null)
{
// probably want to resolve this from container just hard coding as example, assumption is that SiteManager, does the repository bits for you.
return new SiteManager((int)controllerContext.RouteData.Values['siteNum']);
}
return null;
}
#endregion
}
public class RepositoryFactorySelector : DefaultTypedFactoryComponentSelector
{
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
return (method.Name.EndsWith("ById") && arguments.Length >= 1 && arguments[0] is int)
? string.Format("Repository{0}", arguments[0])
: base.GetComponentName(method, arguments);
}
}
public class RepositoryInstaller : IWindsorInstaller
{
#region IWindsorInstaller Members
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<Repository>().Configure(c=>c.Named(c.Implementation.Name)));
container.Register(
Component.For<RepositoryFactorySelector, ITypedFactoryComponentSelector>().LifestyleSingleton(),
Component.For<IRepositoryFactory>().AsFactory(c => c.SelectedWith<RepositoryFactorySelector>()));
}
#endregion
}
按如下方式注册您的存储库:
public class SiteManagerModelBinder : IModelBinder
{
#region IModelBinder Members
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.Model != null)
{
throw new InvalidOperationException("Cannot update instances");
}
// Apply your condition to determine if site number is in Url.
if (controllerContext.RouteData.Values['siteNum']!=null)
{
// probably want to resolve this from container just hard coding as example, assumption is that SiteManager, does the repository bits for you.
return new SiteManager((int)controllerContext.RouteData.Values['siteNum']);
}
return null;
}
#endregion
}
public class RepositoryFactorySelector : DefaultTypedFactoryComponentSelector
{
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
return (method.Name.EndsWith("ById") && arguments.Length >= 1 && arguments[0] is int)
? string.Format("Repository{0}", arguments[0])
: base.GetComponentName(method, arguments);
}
}
public class RepositoryInstaller : IWindsorInstaller
{
#region IWindsorInstaller Members
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<Repository>().Configure(c=>c.Named(c.Implementation.Name)));
container.Register(
Component.For<RepositoryFactorySelector, ITypedFactoryComponentSelector>().LifestyleSingleton(),
Component.For<IRepositoryFactory>().AsFactory(c => c.SelectedWith<RepositoryFactorySelector>()));
}
#endregion
}
请参考my global.asax.cs:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
Container = new WindsorContainer();
Container.AddFacility<TypedFactoryFacility>();
Container.Install(FromAssembly.This());
var controllerFactory = new WindsorControllerFactory(Container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}
public WindsorContainer Container;
}
更新了我的问题并回答了您的回答。看起来很有希望,但这是一个仅适用于基本/通用MVC的解决方案,还是也适用于Web API,因为我的控制器实现了ApicController而不是Controller:public class DepartmentsController:ApiControllerNo,URI在应用程序\u start中不可访问,这正是您注册应用程序范围的东西的地方。我不太确定web API,但据我所知,它与largley一样,并通过相同的管道。尝试一下,让我知道,我可以想出其他方法来实现解决方案。有几种方法可以做到这一点,如果愿意,您可以直接用SiteRepository替换SiteManager,但是中间有一个额外的业务层总是好的。没关系,您只需要注册它。它甚至可以在不同的组件中。这一切看起来都很聪明,但我没有“观点”;这是Web API,不是MVC。