首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >抽象泛型ODataController类导致“找不到HTTP资源”

抽象泛型ODataController类导致“找不到HTTP资源”
EN

Stack Overflow用户
提问于 2014-01-14 06:21:56
回答 2查看 3.7K关注 0票数 19

我尝试在VS2013中抽象自动生成的ODataController类,因为代码在不同的控制器上看起来是相同的,除了POCO的名称,所以,我做了以下操作:

代码语言:javascript
复制
 public abstract class ODataControllerBase<T,DB> : ODataController
        where T : class, IIdentifiable, new()
        where DB : DbContext, new() 
 {
     protected DB _DataContext;

     public ODataControllerBase() : base()
     {
         _DataContext = new DB();
     }

     // only one function shown for brevity
     [Queryable]
     public SingleResult<T> GetEntity([FromODataUri] int key)
     {
         return SingleResult.Create(_DataContext.Set<T>().Where(Entity => Entity.Id.Equals(key)));
     }  
 }

IIdentifiable是一个强制T参数具有可读/可写Id整数属性的接口。

实现如下所示(POCOs和DataContexts应该已经创建好了)

代码语言:javascript
复制
public class MyObjectsController : ODataControllerBase<MyObject,MyDbContext>
{
    public MyObjectsController() : base()
    {
    }

    // That's it - done because all the repetitive code has been abstracted.
}

现在,我的WebApiConfig的Register函数只包含以下内容:

代码语言:javascript
复制
public static void Register(HttpConfiguration config)
{
    ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
    builder.EntitySet<MyObject>("MyObjects");
    config.Routes.MapODataRoute("odata", "odata", builder.GetEdmModel());  
}

我运行了这个项目,http://localhost:10000/odata/MyObjects,我得到了响应:

代码语言:javascript
复制
<m:error>
   <m:code/>
   <m:message xml:lang="en-US">No HTTP resource was found that 
      matches the request URI `http://localhost:10000/odata/MyObjects.`
   </m:message>
   <m:innererror>
       <m:message>No routing convention was found to select an action 
            for the OData path with template '~/entityset'.
       </m:message>
       <m:type/>
       <m:stacktrace/>
   </m:innererror>
 </m:error>

遗漏了什么?我应该删除什么?这是不是我们不能做的事情,也就是说,我们真的需要直接继承ODataController而不需要中间父类吗?

EN

回答 2

Stack Overflow用户

发布于 2017-03-12 05:21:22

在我们的一个项目中,我们还使用了一个通用的ODataController基类,其中我们实际使用GetEntity来检索单个实体,使用GetEntitySet来检索实体列表。

根据您提供的URL和产生的错误消息,ODATA框架无法找到~/entityset的ODataAction。由于您已经给出了http://localhost:10000/odata/MyObjects作为示例,所讨论的操作不能是public SingleResult<T> GetEntity([FromODataUri] int key),因为这只对应于像这样的http://localhost:10000/odata/MyObjects(42)这样的查询。

我们的泛型控制器代码如下所示:

代码语言:javascript
复制
public abstract class OdataControllerBase<T> : ODataController
    where T : class, IIdentifiable, new()
{
    protected OdataControllerBase(/* ... */)
        : base()
    {
        // ...
    }

    public virtual IHttpActionResult GetEntity([FromODataUri] long key, ODataQueryOptions<T> queryOptions)
    {
        // ...

        return Ok(default(T));
    }

    public virtual async Task<IHttpActionResult> GetEntitySet(ODataQueryOptions<T> queryOptions)
    {
        // ...

        return Ok<IEnumerable<T>>(default(List<T>));
    }

    public virtual IHttpActionResult Put([FromODataUri] long key, T modifiedEntity)
    {
        // ...

        return Updated(default(T));
    }

    public virtual IHttpActionResult Post(T entityToBeCreated)
    {
        // ...

        return Created(default(T));
    }

    [AcceptVerbs(HTTP_METHOD_PATCH, HTTP_METHOD_MERGE)]
    public virtual IHttpActionResult Patch([FromODataUri] long key, Delta<T> delta)
    {
        // ...

        return Updated(default(T));
    }

    public virtual IHttpActionResult Delete([FromODataUri] long key)
    {
        // ...

        return Updated(default(T));
    }
}

然后,特定控制器的代码如下所示:

代码语言:javascript
复制
public partial class KeyNameValuesController : OdataControllerBase<T>
{
    public KeyNameValuesController(/* ... */)
        : base()
    {
        // there is nothing to be done here
    }
}

然而,我们发现这两个Get方法(对于单个结果和可枚举结果)实际上都必须以Get开头。首先,我们尝试了List而不是GetEntitySet,但这并不起作用,因为框架随后期望List操作的POST )。

实际上,您可以通过提供Routing and Action Selection in ASP.NET Web API中描述的自定义IHttpActionSelector来验证和诊断解析过程(查看ASP.NET WEB API 2: HTTP Message Lifecycle可能也是值得的)。

因此,实际上可以像您最初在示例中尝试的那样使用GetEntity作为方法名,并且不需要将其重命名为simple Get。此外,不需要对ODATA配置进行任何修改。

票数 2
EN

Stack Overflow用户

发布于 2015-03-13 00:18:01

为了确定要调用的操作,框架使用路由表。Web API的Visual Studio项目模板创建默认路由:

代码语言:javascript
复制
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

按操作名称路由

对于默认的路由选择模板,Web API使用HTTP方法来选择操作。但是,您也可以在URI中包含操作名称的情况下创建路由:

代码语言:javascript
复制
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);

我将config配置如下:

代码语言:javascript
复制
config.Routes.MapHttpRoute(
            name: "GetMessage",
            routeTemplate: "api/{controller}/{action}/{quoteName}",
            defaults: new { quoteName = RouterParameters.Optional }
        );

如下所示访问您的URI:

代码语言:javascript
复制
http://localhost:42201/api/Extract/GetMessage/Q3

代码语言:javascript
复制
http://localhost:42201/api/Extract/GetMessage/?quotename=Q3
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21102561

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档