我最近有一個原因需要將一個服務棧服務從.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
我仍然有點無所適從,的該怎麼做解決我原來的問題 - 所以我會很感激任何幫助。
是的,我知道這件事,因爲我的一位同事在SS論壇上發佈了這個消息 - 感謝您添加此帖的鏈接。這不是真正解決問題的答案。我想如果有足夠多的人對這個問題感興趣,那麼他們會做一些狡猾的事來解決問題。不幸的是我不能將這個標記爲答案 - 但是對我有+1 +1 – Jay