添加新的 OData 控制器使现有控制器失败 [英] Adding a new OData controller fails existing controller

查看:24
本文介绍了添加新的 OData 控制器使现有控制器失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从两个 Web API OData 示例构建一个示例,它们中的每一个都可以作为一个单独的项目正常工作.但是当我添加第二个 ODataController 类时,该站点不再工作,抱怨以前工作的 OData 路径模板.以下是更多详细信息:

I am building a sample from two Web API OData samples, each of them works fine as a separate project. But when I add second ODataController class, then the site no longer works complaining about OData path templates that worked previously. Here are more details:

只要其控制器 (ProductsController) 是唯一的控制器,以下操作就可以正常工作:

The following action works fine as long as its controller (ProductsController) is the only controller:

[HttpGet]
[ODataRoute("GetSalesTaxRate(state={state})")]
public IHttpActionResult GetSalesTaxRate([FromODataUri] string state)
{
    return Ok(GetRate(state));
}

现在我添加了一个带有一些操作的新控制器 (MoviesController).

Now I add a new controller (MoviesController) with a few actions.

我扩展了 Owin Startup 类,所以它看起来像这样:

I extend Owin Startup class so it looks like this:

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) 时,出现以下错误:

However, when I try to execute a Web request (URLBASE/functions/$metadata), I get the following error:

System.InvalidOperationException路径模板'GetSalesTaxRate(state={state})' 在操作 'GetSalesTaxRate' 中控制器产品"不是有效的 OData 路径模板.资源不找到GetSalesTaxRate"段.

System.InvalidOperationExceptionThe path template 'GetSalesTaxRate(state={state})' on the action 'GetSalesTaxRate' in controller 'Products' is not a valid OData path template. Resource not found for the segment 'GetSalesTaxRate'.

控制器被映射到不同的路由(功能"和动作").会不会是每个路由都映射到了自己的 EdmModel 上的问题?

Controllers are mapped to different routes ("functions" and "actions"). Can be that the problem is that each route is mapped to its own EdmModel?

更新.我检查过我可以添加更多控制器,只要它们引用相同的 EDM 模型.但是一旦我引入了第二个模型(并从 MapODataServiceRoute 引用它),那么整个服务就会中断.是否有支持多种模型的解决方法?

UPDATE. I checked that I can add more controllers as long as they refer to the same EDM model. But once I introduce a second model (and reference it from MapODataServiceRoute), then the whole service breaks. Is there any workaround to support multiple models?

更新 2. 如果我继承 DefaultHttpControllerTypeResolver 并且只启用单个控制器(其中任何一个),那么也可以正常工作.但我仍然不解为什么使用不同模型的多个控制器会失败.

UPDATE 2. If I subclass DefaultHttpControllerTypeResolver and only enable single controller (any of them), then is also works fine. But I am still puzzled why multiple controllers using different models fail.

推荐答案

默认情况下,映射 OData 属性路由约定时,HTTP 控制器选择器 IHttpControllerSelector 的默认逻辑使用 HttpConfiguration 的 DefaultAssembloesResolver,它将查找应用程序域中的所有控制器类型.范围可以缩小到属于模型的控制器.

By default, when map OData attribute route conventions, the default logic of HTTP controller selector IHttpControllerSelector uses HttpConfiguration's DefaultAssembloesResolver, which will look up all controller types in an app domain. The scope could be reduced to controllers belong to a model.

我们可以自定义 MapODataServiceRoute 扩展方法.一些代码片段:

We can customize the MapODataServiceRoute extension methods. Some code snippet:

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

这篇关于添加新的 OData 控制器使现有控制器失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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