我正在从两个Web API OData示例构建一个示例,每个示例都可以作为一个单独的项目正常工作。但是当我添加第二个ODataController类时,该站点不再适用于以前工作的OData路径模板。以下是更多细节:
只要控制器(ProductsController)是唯一的控制器,以下操作就可以正常工作:
[HttpGet]
[ODataRoute("GetSalesTaxRate(state={state})")]
public IHttpActionResult GetSalesTaxRate([FromODataUri] string state)
{
return Ok(GetRate(state));
}
现在我添加一个新的控制器(MoviesController),其中包含一些操作。
我扩展Owin Startup类,看起来像这样:
public void Configuration(IAppBuilder builder)
{
var config = new HttpConfiguration();
config.MapODataServiceRoute(routeName: "functions route", routePrefix: "functions", model: FunctionStartup.GetEdmModel());
config.MapODataServiceRoute(routeName: "actions route", routePrefix: "actions", model: ActionStartup.GetEdmModel());
builder.UseWebApi(config);
}
但是,当我尝试执行Web请求(URLBASE / functions / $ metadata)时,出现以下错误:
System.InvalidOperationException路径模板 'GetSalesTaxRate'中的'GetSalesTaxRate(state = {state})' controller'Products'不是有效的OData路径模板。资源没有 找到了段'GetSalesTaxRate'。
控制器映射到不同的路由(“功能”和“操作”)。可能是问题是每条路由都映射到自己的EdmModel?
更新。我检查过我可以添加更多控制器,只要它们引用相同的EDM模型。但是,一旦我引入第二个模型(并从MapODataServiceRoute引用它),整个服务就会中断。有没有解决方法来支持多个模型?
UPDATE 2.如果我继承DefaultHttpControllerTypeResolver并且只启用单个控制器(其中任何一个),那么也可以正常工作。但我仍然感到困惑,为什么使用不同模型的多个控制器都会失败。
答案 0 :(得分:5)
默认情况下,当映射OData属性路由约定时,HTTP控制器选择器IHttpControllerSelector的默认逻辑使用HttpConfiguration的DefaultAssembloesResolver,它将查找应用程序域中的所有控制器类型。范围可以简化为属于模型的控制器。
我们可以自定义MapODataServiceRoute扩展方法。一些代码段:
public class Startup
{
public void Configuration(IAppBuilder builder)
{
var config = new HttpConfiguration();
config.CustomMapODataServiceRoute(routeName: "functions route", routePrefix: "functions",
model: FunctionStartup.GetEdmModel(),
controllers: new[] { typeof(ProductsController) });
config.CustomMapODataServiceRoute(routeName: "actions route", routePrefix: "actions",
model: ActionStartup.GetEdmModel(),
controllers: new[] { typeof(MoviesController) });
config.EnsureInitialized();
builder.UseWebApi(config);
}
}
public class CustomAttributeRoutingConvention : AttributeRoutingConvention
{
private readonly List<Type> _controllers = new List<Type> { typeof(MetadataController) };
public CustomAttributeRoutingConvention(IEdmModel model, HttpConfiguration configuration, IEnumerable<Type> controllers)
: base(model, configuration)
{
_controllers.AddRange(controllers);
}
public override bool ShouldMapController(HttpControllerDescriptor controller)
{
return _controllers.Contains(controller.ControllerType);
}
}
public static class HttpConfigExt
{
public static ODataRoute CustomMapODataServiceRoute(this HttpConfiguration configuration, string routeName,
string routePrefix, IEdmModel model, IEnumerable<Type> controllers)
{
var routingConventions = ODataRoutingConventions.CreateDefault();
routingConventions.Insert(0, new CustomAttributeRoutingConvention(model, configuration, controllers));
return configuration.MapODataServiceRoute(routeName, routePrefix, model, new DefaultODataPathHandler(),
routingConventions);
}
}