GVKun编程网logo

c# – 使用媒体类型版本化ASP.NET Web API 2(c# mediaplayer类)

29

这篇文章主要围绕c#–使用媒体类型版本化ASP.NETWebAPI2和c#mediaplayer类展开,旨在为您提供一份详细的参考资料。我们将全面介绍c#–使用媒体类型版本化ASP.NETWebAPI

这篇文章主要围绕c# – 使用媒体类型版本化ASP.NET Web API 2c# mediaplayer类展开,旨在为您提供一份详细的参考资料。我们将全面介绍c# – 使用媒体类型版本化ASP.NET Web API 2的优缺点,解答c# mediaplayer类的相关问题,同时也会为您带来ASP.NET Core Web API不支持的媒体类型、ASP.NET Core WebAPI:不支持的媒体类型 - HTTP 415、ASP.NET Web API操作使用接口而不是具体类、asp.net web-api – ASP.net Web API RESTful Web服务基本身份验证的实用方法。

本文目录一览:

c# – 使用媒体类型版本化ASP.NET Web API 2(c# mediaplayer类)

c# – 使用媒体类型版本化ASP.NET Web API 2(c# mediaplayer类)

我正在使用具有属性路由的ASP.NET Web API 2,但我似乎无法使用媒体类型application / vnd.company [.version] .param [json]获得版本控制.

我收到以下错误:

The given key was not present in the dictionary.

它来源于FindActionMatchrequiredRouteAndQueryParameters()方法中的关键_actionParameterNames [descriptor].

foreach (var candidate in candidatesFound)
{
        HttpActionDescriptor descriptor = candidate.ActionDescriptor;
        if (IsSubset(_actionParameterNames[descriptor],candidate.CombinedParameterNames))
        {
            matches.Add(candidate);
        }
}

资料来源:ApiControllerActionSelector.cs

进一步调试后,我意识到如果你有两个控制器

[RoutePrefix("api/people")]
public class PeopleController : BaseApiController
{
    [Route("")]
    public HttpResponseMessage GetPeople()
    {
    }

    [Route("identifier/{id}")]
    public HttpResponseMessage GetPersonById()
    {
    }
}

[RoutePrefix("api/people")]
public class PeopleV2Controller : BaseApiController
{     
    [Route("")]
    public HttpResponseMessage GetPeople()
    {
    } 

    [Route("identifier/{id}")]
    public HttpResponseMessage GetPersonById()
    {
    }
}

您不能使用您的自定义ApiVersioningSelector : DefaultHttpControllerSelector,因为它将测试所有键,如上所述,具有相同[RoutePrefix(“api / people”)]的所有控制器,显然会抛出异常.

只是为了确保选择了正确的控制器

我不知道这是否是一个错误,但是使用路由[RoutePrefix(“api / v1 / people”)]到版本API让我很伤心.

注意:没有属性路由,这很有效.

UPDATE

public class ApiVersioningSelector : DefaultHttpControllerSelector
    {
        private HttpConfiguration _HttpConfiguration;
        public ApiVersioningSelector(HttpConfiguration httpConfiguration)
            : base(httpConfiguration)
        {
            _HttpConfiguration = httpConfiguration;
        }



        public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
        {
            IDictionary<string,HttpControllerDescriptor> controllers = GetControllerMapping();                                             

            var attributedRoutesData = request.GetRouteData().GetSubroutes();
            var subrouteData = attributedRoutesData.LastOrDefault(); //LastOrDefault() will get PeopleController,FirstOrDefault will get People{version}Controller which we don't want

            var actions = (ReflectedHttpActionDescriptor[])subrouteData.Route.DataTokens["actions"];
            var controllerName = actions[0].ControllerDescriptor.ControllerName;


            //For controller name without attribute routing
            //var controllerName = (string)routeData.Values["controller"];

            HttpControllerDescriptor oldControllerDescriptor;
            if (controllers.TryGetValue(controllerName,out oldControllerDescriptor))
            {
                var apiVersion = GetVersionFromMediaType(request);

                var newControllerName = String.Concat(controllerName,"V",apiVersion);

                HttpControllerDescriptor newControllerDescriptor;
                if (controllers.TryGetValue(newControllerName,out newControllerDescriptor))
                {
                    return newControllerDescriptor;
                }
                return oldControllerDescriptor;
            }
            return null;
        }


        private string GetVersionFromMediaType(HttpRequestMessage request)
        {
            var acceptHeader = request.Headers.Accept;

            var regularExpression = new Regex(@"application\/vnd\.mycompany\.([a-z]+)\.v([0-9]+)\+json",RegexOptions.IgnoreCase);

            foreach (var mime in acceptHeader)
            {
                var match = regularExpression.Match(mime.MediaType);
                if (match != null)
                {
                    return match.Groups[2].Value;
                }
            }
            return "1";
        }

    }

解决方法

感谢您分享您的代码.我已经修改了您的版本控制器选择器,如下所示,并尝试了一些情况,它似乎工作正常.您可以尝试如下更新您的控制器选择器,看看它是否有效?
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
    {
        HttpControllerDescriptor controllerDescriptor = null;

        // get list of all controllers provided by the default selector
        IDictionary<string,HttpControllerDescriptor> controllers = GetControllerMapping();

        IHttpRouteData routeData = request.GetRouteData();

        if (routeData == null)
        {
            throw new HttpResponseException(HttpStatusCode.NotFound);
        }

        //check if this route is actually an attribute route
        IEnumerable<IHttpRouteData> attributeSubroutes = routeData.GetSubroutes();

        var apiVersion = GetVersionFromMediaType(request);

        if (attributeSubroutes == null)
        {
            string controllerName = GetRouteVariable<string>(routeData,"controller");
            if (controllerName == null)
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }

            string newControllerName = String.Concat(controllerName,apiVersion);

            if (controllers.TryGetValue(newControllerName,out controllerDescriptor))
            {
                return controllerDescriptor;
            }
            else
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
        }
        else
        {
            // we want to find all controller descriptors whose controller type names end with
            // the following suffix(ex: CustomersV1)
            string newControllerNameSuffix = String.Concat("V",apiVersion);

            IEnumerable<IHttpRouteData> filteredSubroutes = attributeSubroutes.Where(attrRouteData =>
            {
                HttpControllerDescriptor currentDescriptor = GetControllerDescriptor(attrRouteData);

                bool match = currentDescriptor.ControllerName.EndsWith(newControllerNameSuffix);

                if (match && (controllerDescriptor == null))
                {
                    controllerDescriptor = currentDescriptor;
                }

                return match;
            });

            routeData.Values["MS_Subroutes"] = filteredSubroutes.ToArray();
        }

        return controllerDescriptor;
    }

    private HttpControllerDescriptor GetControllerDescriptor(IHttpRouteData routeData)
    {
        return ((HttpActionDescriptor[])routeData.Route.DataTokens["actions"]).First().ControllerDescriptor;
    }

    // Get a value from the route data,if present.
    private static T GetRouteVariable<T>(IHttpRouteData routeData,string name)
    {
        object result = null;
        if (routeData.Values.TryGetValue(name,out result))
        {
            return (T)result;
        }
        return default(T);
    }

ASP.NET Core Web API不支持的媒体类型

ASP.NET Core Web API不支持的媒体类型

在正文请求中,您正在发送无效的JSON。您不会在标题中设置内容类型。

要在POSTMAN中解决此问题,请单击“文本”,然后从下拉列表中选择JSON选项。然后添加打开和闭合的括号。这样您会收到一个HTTP 400代码。按照以下代码片段发送对象。

{
    "FirstName":"Tom","LastName":"Anderson","Address":"Boston"
}

For detail information,click here

,

是的,在邮递员内部,我不得不将标题从text / plain更改为application / json!

谢谢你的建议!

ASP.NET Core WebAPI:不支持的媒体类型 - HTTP 415

ASP.NET Core WebAPI:不支持的媒体类型 - HTTP 415

如何解决ASP.NET Core WebAPI:不支持的媒体类型 - HTTP 415?

我尝试创建一个新部门,但出现此错误:

{
    "type":"https://tools.ietf.org/html/rfc7231#section-6.5.13","title":"Unsupported Media Type","status":415,"traceId":"|3361f693-4c3294040da78eae."
}  

谁能告诉我为什么会出现这个错误?我也不能对部门做其他粗鲁的操作。

这是我的部门主管

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using WebAPI.Models;

namespace WebAPI.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class DepartmentsController : Controller
    {
        private readonly EmployeeDbContext _context;

        public DepartmentsController(EmployeeDbContext context)
        {
            _context = context;
        }

        // GET: Departments
        [HttpGet]
        public async Task<IActionResult> Index(string sortOrder,string currentFilter,string searchString,int? pageNumber)
        {
            ViewData["CurrentSort"] = sortOrder;
            ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
     
            if (searchString != null)
            {
                pageNumber = 1;
            }
            else
            {
                searchString = currentFilter;
            }

            ViewData["CurrentFilter"] = searchString;

            var departments = from d in _context.Departments
                              select d;

            if (!String.IsNullOrEmpty(searchString))
            {
                departments = departments.Where(d => d.departmentName.Contains(searchString)
                               || d.departmentName.Contains(searchString));
            }

            int pageSize = 3;

            return View(await PaginatedList<Department>.CreateAsync(departments.AsNoTracking(),pageNumber ?? 1,pageSize));
        }

        // GET: Departments/Details/5
        public async Task<IActionResult> Details(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var department = await _context.Departments
                .FirstOrDefaultAsync(m => m.Id == id);

            if (department == null)
            {
                return NotFound();
            }

            return View(department);
        }

        // GET: Departments/Create
        [HttpGet]
        public IActionResult Create()
        {
            return View();
        }

        [HttpPost,ActionName("Create")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create([Bind("departmentName")] Department department)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    _context.Add(department);
                    await _context.SaveChangesAsync();
                    return RedirectToAction(nameof(Index));
                }
            }
            catch (dbupdateException /* ex */)
            {
                //Log the error (uncomment ex variable name and write a log.
                ModelState.AddModelError("","Unable to save changes. " +
                    "Try again,and if the problem persists " +
                    "see your system administrator.");
            }

            return View(department);
        }

        // GET: Departments/Edit/5
        public async Task<IActionResult> Edit(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var department = await _context.Departments.FindAsync(id);

            if (department == null)
            {
                return NotFound();
            }

            return View(department);
        }

        // POST: Departments/Edit/5
        // To protect from overposting attacks,enable the specific properties you want to bind to,for 
        // more details,see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost,ActionName("Edit")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id,[Bind("Id,departmentName")] Department department)
        {
            if (id != department.Id)
            {
                return NotFound();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(department);
                    await _context.SaveChangesAsync();
                }
                catch (dbupdateConcurrencyException)
                {
                    if (!DepartmentExists(department.Id))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }

                return RedirectToAction(nameof(Index));
            }

            return View(department);
        }

        // GET: Departments/Delete/5
        public async Task<IActionResult> Delete(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var department = await _context.Departments
                .FirstOrDefaultAsync(m => m.Id == id);

            if (department == null)
            {
                return NotFound();
            }

            return View(department);
        }

        // POST: Departments/Delete/5
        [HttpPost,ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteConfirmed(int id)
        {
            var department = await _context.Departments.FindAsync(id);
            _context.Departments.Remove(department);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }

        private bool DepartmentExists(int id)
        {
            return _context.Departments.Any(e => e.Id == id);
        }
    }
}

这是我的 Department 模型类:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace WebAPI.Models
{
    public class Department
    {
        [Key]
        public int Id { get; set; }

        [required(ErrorMessage = "Please enter Department Name")]
        [display(Name = "Department Name")]
        public String departmentName { get; set; }

        // Navigation Properties
        public ICollection<Employee> Employees { get; set; }
    }
}

创建视图

@Sergey `@model WebAPI.Models.Department

@{
    ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>Department</h4>
<hr />
<div>
    <div>
        <form asp-action="Create" >
            <div asp-validation-summary="ModelOnly"></div>
            <div>
                <label asp-for="departmentName"></label>
                <input asp-for="departmentName"/>
                <span asp-validation-for="departmentName"></span>
            </div>
            <div>
                <input type="submit" value="Create"/>
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
    @* <a asp-action="Index">Back to List</a>*@
</div>

@section Scripts {
    <script>
        // Add the following code if you want the name of the file appear on select
        $(".custom-file-input").on("change",function () {
            var fileName = $(this).val().split("\\").pop();
            $(this).siblings(".custom-file-label").addClass("selected").html(fileName);
        });
    </script>
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
`

解决方法

删除 [ApiController] 并修复控制器操作:

       [HttpGet]
        public IActionResult Create()
        {
            var model=new Department();
            return View(model);
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create( Department department)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    _context.Add(department);
                    await _context.SaveChangesAsync();
                    return RedirectToAction(nameof(Index));
                }
            }
            catch (DbUpdateException /* ex */)
            {
                //Log the error (uncomment ex variable name and write a log.
                ModelState.AddModelError("","Unable to save changes. " +
                    "Try again,and if the problem persists " +
                    "see your system administrator.");
            }

            return View(department);
        }

并查看

<form asp-action="Create" asp-controller"Departments" "method="post" >
 <div asp-validation-summary="ModelOnly"></div>
  <input type="hidden" asp-for="Id" value="@Model.Id" />
            .....
        </form>

ASP.NET Web API操作使用接口而不是具体类

ASP.NET Web API操作使用接口而不是具体类

我的团队需要使用此框架为我们的公司和产品开发框架.
其中一个要求是可以为特定客户定制产品,但应该使用同一产品的其他版本(不是自动)轻松更新.

我们正在使用ASP.NET MVC 4 Web API(目前,基于我们的框架,将在明年创建桌面产品),NHibernate,使用Autofac作为DI容器和N层的IoC.

因此,在WebApp的某些方面,我们将viewmodels用作具有一个默认实现的接口,并使用Autofac链接它们,并且在期货自定义中很容易更改.

在ASP.NET MVC中,我们实现了这个实现IModelBinderProvider并创建一个自定义类来激活DefaultModelBinder:

像这样的东西:

public class MyCustomMVCModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(Type modelType)
    {
        if (modelType.IsInterface)
            return new MyCustomMVCModelBinder();

        return new DefaultModelBinder();
    }
}
public class MyCustomMVCModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext)
    {
        var context = new ModelBindingContext(bindingContext);
        var item = DependencyResolver.Current.GetService(bindingContext.ModelType);

        Func<object> modelAccessor = () => item;
        context.ModelMetadata = new ModelMetadata(new DataAnnotationsModelMetadataProvider(),bindingContext.ModelMetadata.ContainerType,modelAccessor,item.GetType(),bindingContext.ModelName);

        return base.BindModel(controllerContext,context);
    }
}

在我的控制器中,我只使用接口作为参数.因此,它工作正常,因为值正确填充.

但是,如何在Web API中使用正确绑定的值执行相同操作?
我尝试实现IModelBinder并继承ModelBinderProvider.我可以获得接口实现的实例,但不会填充值.

这是WebAPI中的尝试实现:

public class MyCustomWebAPIModelBinderProvider : ModelBinderProvider
{
    public override IModelBinder GetBinder(System.Web.Http.HttpConfiguration configuration,Type modelType)
    {
        return new MyCustomWebAPIModelBinder();
    }
}

public class MyCustomWebAPIModelBinder : IModelBinder
{
    public bool BindModel(System.Web.Http.Controllers.HttpActionContext actionContext,ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType.IsInterface)
        {
            var item = GlobalConfiguration.Configuration.DependencyResolver.GetService(bindingContext.ModelType);

            if (item != null)
            {
                Func<object> modelAccessor = () => item;
                var a = bindingContext.ModelMetadata.ContainerType;
                var b = modelAccessor;
                var c = item.GetType();
                var d = bindingContext.ModelName;

                bindingContext.ModelMetadata = new ModelMetadata(new DataAnnotationsModelMetadataProvider(),a,b,c,d);

                bindingContext.Model = item;

                return true;
            }
        }

        return false;
    }
}

我错过了什么?
有可能做我们想要的吗?

解决方法

而不是使用ModelBinder,使用MediaTypeFormatter的实现.

您可以覆盖方法“ReadFromStreamAsync”并将类型更改为您需要的任何类型.

在下面的示例中,通过使用MVC的DependencyResolver解析具体类型来更改类型,对WebAPI可以正常工作.

public class CustomFormUrlEncodedMediaTypeFormatter : FormUrlEncodedMediaTypeFormatter
    {
        public CustomFormUrlEncodedMediaTypeFormatter() : base() { }

        public override Task ReadFromStreamAsync(Type type,Stream readStream,HttpContent content,IFormatterLogger formatterLogger)
        {
            if (type.IsInterface)
                type = GetConcreteType(type);

            return base.ReadFromStreamAsync(type,readStream,content,formatterLogger);
        }

        public override Task WritetoStreamAsync(Type type,object value,Stream writeStream,TransportContext transportContext)
        {
            if (type.IsInterface)
                type = GetConcreteType(type);

            return base.WritetoStreamAsync(type,value,writeStream,transportContext);
        }

        private Type GetConcreteType(Type type)
        {
            object concrete = System.Web.Mvc.DependencyResolver.Current.GetService(type);
            return concrete.GetType();
        }
    }

如果你想用JsonFormatter做到这一点,那么为Json.NET创建一个“CustomCreationConverter”是一个更好的方法,而不是解决你的界面中所有子对象的依赖性.

public class DomainConverter : CustomCreationConverter
    {
            public DomainConverter() { }

            public override bool CanConvert(Type objectType)
            {
                return objectType.IsInterface;
            }

            public override object Create(Type objectType)
            {
                return System.Web.Mvc.DependencyResolver.Current.GetService(objectType);
            }
    }

asp.net web-api – ASP.net Web API RESTful Web服务基本身份验证

asp.net web-api – ASP.net Web API RESTful Web服务基本身份验证

我正在使用ASP.Net Web Api实现RESTful Web服务。我已经得出结论使用基本认证SSL做认证部分。什么是最好/正确的方法来实现呢?

我的第一个尝试是手动,解析授权头,解码和验证用户对我的数据库。它的工作,但我不知道,如果我缺少的东西。

我见过一些使用用户角色和原则的解决方案。虽然我不知道这些实际做什么,我几乎肯定我不会需要这些,因为在我的数据库中,我定义了我自己的用户和他们的角色。

还有我还没有完全理解,是如果服务的消费者必须发送凭证与每个请求或他们以某种方式缓存。我的服务应该做些什么才能发生,还是完全由消费者来处理?

最后一个问题关于客户使用javascript请求。如果他们尝试使用该服务,是否会出现任何“跨域请求”问题?

解决方法

Jamie Kurtze提供了使用基本身份验证在这里 ASP.NET Web API REST Security Basics的一个很好的解释

从我的理解,如果你想要你的请求是无状态的,那么每个请求将需要设置验证字段

Jamie Kurtze在从DelegateHandler派生的类中包装必要的代码,而Rick Strahl使用过滤器检查调用是否有效。你可以在他的博客文章阅读更多在这个主题在A WebAPI Basic Authentication Authorization Filter

关于c# – 使用媒体类型版本化ASP.NET Web API 2c# mediaplayer类的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于ASP.NET Core Web API不支持的媒体类型、ASP.NET Core WebAPI:不支持的媒体类型 - HTTP 415、ASP.NET Web API操作使用接口而不是具体类、asp.net web-api – ASP.net Web API RESTful Web服务基本身份验证等相关内容,可以在本站寻找。

本文标签: