2017-09-04 71 views
3

我最近有一个原因需要将一个服务栈服务从.NET Core 1.1升级到.NET Core 2.0。ServiceStack和.NET Core的根URL 2

以前,我的根在URL节目类有点像这样定义...

IWebHost host = new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup<Startup>() .UseUrls("http://*:44444/api/myservice") .Build(); host.Run();

在.NET核2.0,看来这是不可能指定的根路径'UseUrls'方法 - 我得到一个异常,说System.InvalidOperationException: A path base can only be configured using IApplicationBuilder.UsePathBase()使用合并UsePathBaseMiddleware为了设置根路径。

我发现,当我在WebHostBuilder中指定根路径+端口号并在Apphost文件中设置UsePathBase(在调用app.UseServiceStack(...)之前或之后),一切都可以从根(即我认为我对UsePathBase的调用被忽略?!)。

我的请求都装饰有一个路由属性,它看起来像这样:

[Route("users/{username}", "Get"]

使用.NET 1.1的核心,我能够在
http://[URL]:[PORT]/api/user/users/[USERNAME]

使用.NET访问此服务核心2.0,服务出现在
http://[URL]:[PORT]/users/[USERNAME]

现在,我可以在每个定义的路由属性上硬编码路由以包含'/ api/user'前缀,或者我认为我可以在AppHost的GetRouteAttributes()中执行某些操作来覆盖所有发现的路由并根据需要应用前缀 - 但元数据页面总是出现在根地址(即http://[URL]:[PORT]/metadata)而不是http://[URL]:[PORT]/api/[SERVICE]/metadata

这对我来说是一个问题,因为我在同一个公共URL(该端口被API网关隐藏)中有几十个服务,所以我需要元数据页面出现在除根之外的其他位置。

有没有一个(最好低影响)的方式来使服务路线的行为像在.NET Core 1.1中一样?


更新 - 18/09/17一点研究


我已经能够找到使这项工作的两种方式后(他们都不理想......)

第一种方式:

这是我的第一个解决方案的完整回购。我想通了如何使用app.UsePathBase更改为根URL,但元数据的详细信息页面不走这条路的基础考虑,因此他们只显示每一个服务的方法从“/”

using Funq; 
using Microsoft.AspNetCore; 
using Microsoft.AspNetCore.Builder; 
using Microsoft.AspNetCore.Hosting; 
using Microsoft.Extensions.DependencyInjection; 
using Microsoft.Extensions.Logging; 
using ServiceStack; 
using System; 
using System.Threading.Tasks; 

namespace ServiceStackCore1Test 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.Title = "My Service"; 

      IWebHost host = WebHost.CreateDefaultBuilder() 
       .UseStartup<Startup>() 
       .UseUrls("http://*:32505/") 
       .Build(); 
      host.Run(); 

     } 
    } 

    internal class PathSetupStartupFilter : IStartupFilter 
    { 
     public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next) 
     { 
      return app => 
      { 
       app.UsePathBase("/api/myservice"); 
       next(app); 
      }; 
     } 
    } 

    public class Startup 
    { 
     public void ConfigureServices(IServiceCollection services) 
     { 
      services.AddLogging(); 
      services.AddTransient<IStartupFilter, PathSetupStartupFilter>(); 

     } 

     public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
     { 

      loggerFactory.AddConsole((x, y) => y > LogLevel.Trace); 
      app.UseServiceStack(Activator.CreateInstance<AppHost>()); 

      app.Run(context => Task.FromResult(0) as Task); 
     } 
    } 

    public class AppHost : AppHostBase 
    { 
     public AppHost() 
      : base("ASM Cloud - My Service", typeof(MyService).GetAssembly()) 
     { 
     } 

     /// <summary> 
     /// Configure the given container with the 
     /// registrations provided by the funqlet. 
     /// </summary> 
     /// <param name="container">Container to register.</param> 
     public override void Configure(Container container) 
     { 
      this.Plugins.Add(new PostmanFeature()); 
     } 
    } 

    public class MyService : Service 
    { 
     public TestResponse Any(TestRequest request) 
     { 
      //throw new HttpError(System.Net.HttpStatusCode.NotFound, "SomeErrorCode"); 
      return new TestResponse { StatusCode = 218, UserName = request.UserName }; 
     } 

     [Route("/test/{UserName}", "GET", Summary = "test")] 
     public class TestRequest : IReturn<TestResponse> 
     { 

      public string UserName { get; set; } 
     } 

     public class TestResponse : IHasStatusCode 
     { 
      public int StatusCode { get; set; } 
      public string UserName { get; set; } 
     } 

    } 
} 

第二种方式开始 - 这确实提供了正确的功能 - 用于服务路由和元数据显示,但Servicestack在每次调用时解析路径时都会引发异常。在这个完整的repo中,我使用HandlerFactoryPath来设置我的基本URI,根据servicestack文档应该指定应用程序的基本路由。

using Funq; 
using Microsoft.AspNetCore; 
using Microsoft.AspNetCore.Builder; 
using Microsoft.AspNetCore.Hosting; 
using Microsoft.Extensions.DependencyInjection; 
using Microsoft.Extensions.Logging; 
using ServiceStack; 
using System; 
using System.Threading.Tasks; 

namespace ServiceStackCore1Test 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.Title = "My Service"; 

      IWebHost host = WebHost.CreateDefaultBuilder() 
       .UseStartup<Startup>() 
       .UseUrls("http://*:32505/") 
       .Build(); 
      host.Run(); 
     } 
    } 

    public class Startup 
    { 
     public void ConfigureServices(IServiceCollection services) 
     { 
      services.AddLogging(); 
     } 

     public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
     { 
      loggerFactory.AddConsole((x, y) => y > LogLevel.Trace); 
      app.UseServiceStack(Activator.CreateInstance<AppHost>()); 

      app.Run(context => Task.FromResult(0) as Task); 
     } 
    } 

    public class AppHost : AppHostBase 
    { 
     public AppHost() 
      : base("My Service", typeof(MyService).GetAssembly()) 
     { 
     } 

     /// <summary> 
     /// Configure the given container with the 
     /// registrations provided by the funqlet. 
     /// </summary> 
     /// <param name="container">Container to register.</param> 
     public override void Configure(Container container) 
     { 

      Plugins.Add(new PostmanFeature()); 
      SetConfig(new HostConfig 
      { 
       HandlerFactoryPath = "/api/myservice" 
      }); 
     } 
    } 

    public class MyService : Service 
    { 
     public TestResponse Any(TestRequest request) 
     { 
      return new TestResponse { StatusCode = 200, UserName = request.UserName }; 
     } 

     [Route("/test/{UserName}", "GET", Summary = "test")] 
     public class TestRequest : IReturn<TestResponse> 
     { 
      public string UserName { get; set; } 
     } 

     public class TestResponse : IHasStatusCode 
     { 
      public int StatusCode { get; set; } 
      public string UserName { get; set; } 
     } 
    } 
} 

所以,就像我说的,这个解决方案的工作,但会抛出异常

失败:Microsoft.AspNetCore.Server.Kestrel [13] 连接ID “0HL7UFC5AIAO6”,请求ID“0HL7UFC5AIAO6 :00000004“:应用程序抛出未处理的异常。 System.ArgumentOutOfRangeException:startIndex不能大于字符串的长度。 参数名称:startIndex at System.String.Substring(Int32 startIndex,Int32 length) at ServiceStack.AppHostBase.d__7.MoveNext()in C:\ BuildAgent \ work \ 799c742886e82e6 \ src \ ServiceStack \ AppHostBase.NetCore.cs:线101 ---从先前的位置堆栈跟踪,其中引发异常--- 结束在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务task) 在Microsoft.AspNetCore.Hosting.Internal.RequestServicesContainerMiddleware.d__3.MoveNext() ---从以前位置抛出异常的堆栈跟踪结束--- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务task) 在Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Frame 1.<ProcessRequestsAsync>d__2.MoveNext() fail: Microsoft.AspNetCore.Server.Kestrel[13] Connection id "0HL7UFC5AIAO6", Request id "0HL7UFC5AIAO6:00000004": An unhandled exception was thrown by the application. System.ArgumentOutOfRangeException: startIndex cannot be larger than length of string. Parameter name: startIndex at System.String.Substring(Int32 startIndex, Int32 length) at ServiceStack.AppHostBase.<ProcessRequest>d__7.MoveNext() in C:\BuildAgent\work\799c742886e82e6\src\ServiceStack\AppHostBase.NetCore.cs:line 101 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Hosting.Internal.RequestServicesContainerMiddleware.<Invoke>d__3.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Frame 1.d__2.MoveNext()一边

发现,实际的问题(不是我在更新上面显示的东西)可以降低到以下两个问题与ASPNET托管:

https://github.com/aspnet/Hosting/issues/815
https://github.com/aspnet/Hosting/issues/1120

我仍然有点无所适从,的该怎么做解决我原来的问题 - 所以我会很感激任何帮助。

回答

2

不知道你是否曾经找到过这个解决方案,但是servicestack论坛上的某个人有同样的问题(当我开始使用CORE版本的servicestack的时候)。

如果你有机会到论坛,你可以按照进度here

,如果你不这样做,在总结@mythz指出:

“这是他们已经增加了一个重大更改.NET Core 2.0,我们将研究是否有解决方法,但是我会避免与.NET Core约定作斗争,并将其托管在端口上,并使用反向代理来实现所需的基本托管URL。“

+0

是的,我知道这件事,因为我的一位同事在SS论坛上发布了这个消息 - 感谢您添加此帖的链接。这不是真正解决问题的答案。我想如果有足够多的人对这个问题感兴趣,那么他们会做一些狡猾的事来解决问题。不幸的是我不能将这个标记为答案 - 但是对我有+1 +1 – Jay