2017-09-04 27 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