具有 OWIN 自托管的 Web API 无类型 OData 服务返回 406 Not Acceptable

Posted

技术标签:

【中文标题】具有 OWIN 自托管的 Web API 无类型 OData 服务返回 406 Not Acceptable【英文标题】:Web API Typeless OData Service with OWIN self-hosting returns 406 Not Acceptable 【发布时间】:2014-05-12 18:11:52 【问题描述】:

我正在尝试使用 OWIN 自托管设置 Web API 无类型 OData 服务... =)

但为什么不工作? :~(

这是我从各种示例中部分提取的一些代码...

public class Startup
    
        public void Configuration(IAppBuilder appBuilder)
        
            var config = new HttpConfiguration();
            config.Routes.MapHttpRoute("DefaultApi", "api/controller/id",
                new  id = RouteParameter.Optional );
            appBuilder.UseWebApi(config);
        
    

    public class Program
    
        public static IEdmModel Model = GetEdmModel();

        static void Main(string[] args)
        
            using (WebApp.Start<Startup>("http://localhost:8080"))
            
                Console.WriteLine("Running...");
                Console.ReadLine();
            
        

        public static IEdmModel GetEdmModel()
        
            var model = new EdmModel();

            // Create and add product entity type.
            var product = new EdmEntityType("NS", "Product");
            product.AddKeys(product.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32));
            product.AddStructuralProperty("Name", EdmPrimitiveTypeKind.String);
            product.AddStructuralProperty("Price", EdmPrimitiveTypeKind.Double);
            model.AddElement(product);

            // Create and add category entity type.
            var category = new EdmEntityType("NS", "Category");
            category.AddKeys(category.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32));
            category.AddStructuralProperty("Name", EdmPrimitiveTypeKind.String);
            model.AddElement(category);

            // Set navigation from product to category.
            var propertyInfo = new EdmNavigationPropertyInfo();
            propertyInfo.Name = "Category";
            propertyInfo.TargetMultiplicity = EdmMultiplicity.One;
            propertyInfo.Target = category;
            var productCategory = product.AddUnidirectionalNavigation(propertyInfo);

            // Create and add entity container.
            var container = new EdmEntityContainer("NS", "DefaultContainer");
            model.AddElement(container);

            // Create and add entity set for product and category.
            var products = container.AddEntitySet("Products", product);
            var categories = container.AddEntitySet("Categories", category);
            products.AddNavigationTarget(productCategory, categories);

            return model;
        
    

    public class ProductsController : ODataController
    
        private static readonly IQueryable<IEdmEntityObject> Products = Enumerable.Range(0, 10).Select(i =>
        
            var productType = (IEdmEntityType)Program.Model.FindType("NS.Product");
            var categoryType = (IEdmEntityTypeReference)productType.FindProperty("Category").Type;

            var product = new EdmEntityObject(productType);
            product.TrySetPropertyValue("Id", i);
            product.TrySetPropertyValue("Name", "Product " + i);
            product.TrySetPropertyValue("Price", i + 0.01);

            var category = new EdmEntityObject(categoryType);
            category.TrySetPropertyValue("Id", i % 5);
            category.TrySetPropertyValue("Name", "Category " + (i % 5));
            product.TrySetPropertyValue("Category", category);

            return product;
        ).AsQueryable();

        public EdmEntityObjectCollection Get()
        
            // Get Edm type from request.
            var path = this.Request.GetODataPath();
            var edmType = path.EdmType;
            Contract.Assert(edmType.TypeKind == EdmTypeKind.Collection);

            var collectionType = edmType as IEdmCollectionType;
            var entityType = collectionType.ElementType.Definition as IEdmEntityType;
            var model = Request.GetEdmModel();

            var queryContext = new ODataQueryContext(model, entityType);
            var queryOptions = new ODataQueryOptions(queryContext, Request);

            // Apply the query option on the IQueryable here.

            return new EdmEntityObjectCollection(new EdmCollectionTypeReference(collectionType, false), Products.ToList());
        

        public IEdmEntityObject GetProduct(int key)
        
            object id;
            var product = Products.Single(p => HasId(p, key));

            return product;
        

        public IEdmEntityObject GetCategoryFromProduct(int key)
        
            object id;
            var product = Products.Single(p => HasId(p, key));

            object category;
            if (product.TryGetPropertyValue("Category", out category))
            
                return (IEdmEntityObject)category;
            
            return null;
        

        public IEdmEntityObject Post(IEdmEntityObject entity)
        
            // Get Edm type from request.
            var path = Request.GetODataPath();
            var edmType = path.EdmType;
            Contract.Assert(edmType.TypeKind == EdmTypeKind.Collection);

            var entityType = (edmType as IEdmCollectionType).ElementType.AsEntity();

            // Do something with the entity object here.

            return entity;
        

        private bool HasId(IEdmEntityObject product, int key)
        
            object id;
            return product.TryGetPropertyValue("Id", out id) && (int)id == key;
        
    

我得到的结果是:

StatusCode: 406, ReasonPhrase: 'Not Acceptable', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:

  Date: Mon, 12 May 2014 18:08:25 GMT
  Server: Microsoft-HTTPAPI/2.0
  Content-Length: 0

从运行这个:

    var client = new HttpClient();
    var response = client.GetAsync("http://localhost:8080/api/Products").Result;

【问题讨论】:

尝试使用 config.MapODataServiceRoute(...) 方法映射 OData 路由。 【参考方案1】:

如果您使用的是 OData V4,则需要在控制器中进行更改: 老:

using System.Web.Http.OData;

新:

using System.Web.OData;

【讨论】:

以上是关于具有 OWIN 自托管的 Web API 无类型 OData 服务返回 406 Not Acceptable的主要内容,如果未能解决你的问题,请参考以下文章

具有 OWIN 自主机和 Windows 身份验证的 Web Api

asp.net web api 自托管 / owin / katana

在 DELETE 上不允许使用 Owin 自托管 Web API 405 方法

在使用 Owin 自托管的 Web API 中获取远程主机 IP

OWIN 托管的 web api:使用 windows 身份验证并允许匿名访问

如何在 Azure Service Fabric 中的自托管 Web API 上配置 SSL