Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在ASP.NET核心Web Api中进行版本控制_C#_Asp.net_Asp.net Web Api_Asp.net Core - Fatal编程技术网

C# 如何在ASP.NET核心Web Api中进行版本控制

C# 如何在ASP.NET核心Web Api中进行版本控制,c#,asp.net,asp.net-web-api,asp.net-core,C#,Asp.net,Asp.net Web Api,Asp.net Core,在前面的asp.net web api中,我实现了DefaultHttpControllerSelector,以指定我希望请求如何定位我的控制器。我经常使用不同名称的不同控制器,但用于相同的进程。唯一的区别是一个版本比另一个版本高 例如,我可以有一个名为BookingV1Controller的控制器,用于处理服务的版本一。我还需要预订v2controller,它是为处理服务的第二版而设计的。然后,客户端应用程序将使用此urlhttp://myservice.com/api/v2/booking/

在前面的
asp.net web api
中,我实现了
DefaultHttpControllerSelector
,以指定我希望请求如何定位我的控制器。我经常使用不同名称的不同控制器,但用于相同的进程。唯一的区别是一个版本比另一个版本高

例如,我可以有一个名为
BookingV1Controller
的控制器,用于处理服务的版本一。我还需要
预订v2controller
,它是为处理服务的第二版而设计的。然后,客户端应用程序将使用此url
http://myservice.com/api/v2/booking/someaction?id=12
。为了处理请求,我将提供一个
DefaultHttpControllerSelector
的自定义实现,以根据请求的版本选择所需控制器的适当版本

然而,我似乎没有办法在ASP.NET核心中做到这一点。我到处找都没找到。也没有任何文档可以提供帮助

如果有人能在这里帮助我,我将不胜感激。谢谢

更新 我还想知道如果在自定义标题中指定了版本,该怎么办。例如
X-Version:v1

更新2


要求是不应在URL中公开服务的版本。如果不存在版本,服务将返回有关如何添加版本的说明。如果请求的版本中不存在请求的控制器,系统将搜索较低版本。如果它在任何较低版本中找到它,它就会使用它。这样做的原因是为了防止在所有版本上重复使用控制器。但是对于ASP.NET Core,这可能是不可能的。

使用路由属性来控制版本

i、 e


有关从标准Web Api和.NET Core ASP.NET迁移的更多信息,请查看:

我正是在为这个问题绞尽脑汁几天后才为此创建了一个包。它不需要属性

总之,您可以在启动文件中注册IAApplicationModelConversation,该文件可以迭代控制器并基于名称空间注册路由。我创建了一个v1文件夹,并将我的控制器放入其中

实现IApplicationModelConversation的类使用ApplicationModel参数实现Apply方法,该参数将访问应用程序中的控制器及其现有路由。如果我看到一个控制器在我的类中没有设置路由,我将从名称空间获取版本,并使用预定义的URL前缀为该版本生成路由

public void Apply(应用程序模型应用程序){
foreach(application.Controllers中的var控制器){
var hasRouteAttribute=controller.Selectors.Any(x=>x.AttributeRouteModel!=null);
如果(hasRouteAttribute){
继续;
}
var nameSpace=controller.ControllerType.nameSpace.Split('.');
var version=nameSpace.FirstOrDefault(x=>Regex.IsMatch(x,@“[v][\d*]”);
if(string.IsNullOrEmpty(版本)){
继续;
}
controller.Selectors[0]。AttributeRouteModel=new AttributeRouteModel(){
Template=string.Format(urlTemplate,apiPrefix,version,controller.ControllerName)
};
}
}

我在github上有所有的代码,在nuget上也有一个到包的链接

这是我偶然发现的一个非常古老的问题,但现在有更好的解决方案。有这个包裹

Microsoft.AspNetCore.Mvc.Versioning

它有一种功能更加丰富的实现版本控制的方法。其中包括能够使用URL查询字符串、URL路径、标题或自定义版本读取器。能够从HTTPContext等读取版本

简而言之,将以下内容添加到startup.cs中的ConfigureServices方法中

services.AddApiVersioning(o => {
    o.ReportApiVersions = true;
    o.AssumeDefaultVersionWhenUnspecified = true;
            o.DefaultApiVersion = new ApiVersion(1, 0);
});
然后你必须用一个ApiVersion来装饰你的控制器

[ApiVersion("1.0")]
[Route("api/home")]
public class HomeV1Controller : Controller
{
    [HttpGet]
    public string Get() => "Version 1";
}

[ApiVersion("2.0")]
[Route("api/home")]
public class HomeV2Controller : Controller
{
    [HttpGet]
    public string Get() => "Version 2";
}
您还可以通过将其放置在路由中,在路径中实现它

[ApiVersion("1.0")]
[Route("api/{version:apiVersion}/home")]
public class HomeV1Controller : Controller
{
    [HttpGet]
    public string Get() => "Version 1";
}

[ApiVersion("2.0")]
[Route("api/{version:apiVersion}/home")]
public class HomeV2Controller : Controller
{
    [HttpGet]
    public string Get() => "Version 2";
}
当您采用这种方法,通过Microsoft软件包实际实现它时,这也意味着您可以弃用版本、进行版本发现、轻松地从HttpContext访问版本号等。如果只是在您的路径中硬编码,那么您就无法真正做到这一点

有关更多信息(包括在标题中使用):


为此,请将服务API版本控制添加到ASP.NET核心应用程序中

  public void ConfigureServices( IServiceCollection services )
    {
        services.AddMvc();
        services.AddApiVersioning();

        // remaining other stuff omitted for brevity
    }
查询字符串参数版本控制

[ApiVersion( "2.0" )]
[Route( "api/helloworld" )]
public class HelloWorld2Controller : Controller {
    [HttpGet]
    public string Get() => "Hello world!";
}
 [ApiVersion( "1.0" )]
 [Route( "api/v{version:apiVersion}/[controller]" )]
 public class HelloWorldController : Controller {
    public string Get() => "Hello world!";
 }
[ApiVersion( "2.0" )]
[ApiVersion( "3.0" )]
[Route( "api/v{version:apiVersion}/helloworld" )]
public class HelloWorld2Controller : Controller {
    [HttpGet]
    public string Get() => "Hello world v2!";

    [HttpGet, MapToApiVersion( "3.0" )]
    public string GetV3() => "Hello world v3!";
}
这意味着在另一个控制器中以相同的路径获得2.0比1.0,您可以在这里:

/api/helloworld?api版本=2.0

我们可以使用不同的名称空间使用相同的控制器名称

URL路径段版本控制

[ApiVersion( "2.0" )]
[Route( "api/helloworld" )]
public class HelloWorld2Controller : Controller {
    [HttpGet]
    public string Get() => "Hello world!";
}
 [ApiVersion( "1.0" )]
 [Route( "api/v{version:apiVersion}/[controller]" )]
 public class HelloWorldController : Controller {
    public string Get() => "Hello world!";
 }
[ApiVersion( "2.0" )]
[ApiVersion( "3.0" )]
[Route( "api/v{version:apiVersion}/helloworld" )]
public class HelloWorld2Controller : Controller {
    [HttpGet]
    public string Get() => "Hello world v2!";

    [HttpGet, MapToApiVersion( "3.0" )]
    public string GetV3() => "Hello world v3!";
}
标题版本控制

  public void ConfigureServices( IServiceCollection services )
    {
        services.AddMvc();
        services.AddApiVersioning(o => o.ApiVersionReader = new HeaderApiVersionReader("api-version"));
    }
当您执行HeaderAPI版本控制时,您将无法在浏览器中执行GET操作,因此我将使用Postman添加标题(或者我可以使用Curl、WGet、PowerShell或单元测试):


请参考

如果在自定义标题中指定了版本,可以使用什么?或者,没有这样做版本控制,因为最佳做法通常是让URL确定资源位置。如果这样做,您不需要在URL中重复两次版本吗<代码>api/v1/BookingV1和
api/v2/BookingV2
。您需要以这种方式手动将路线写入
[路线(“api/v1/Booking”)]
[路线(“api/v2/Booking”)]
。还是我错了?这就是我必须要做的。通常,如果你这样做,你也会在方法上使用适当的属性。类级属性由类方法继承。如果你想让我们“BookingController”作为唯一的