我正在使用服務堆棧創建自託管REST服務& AppHostHttpListenerBase。我想用我的服務基本URI(例如「API」),像這樣:配置ServiceStack基本URI
http://myserver/api/service1/param
http://myserver/api/service2/param
如何做到這一點無需在每個我的路線定義「API」。在IIS中,我可以設置一個虛擬目錄來隔離服務,但如何在自託管時執行此操作?
我正在使用服務堆棧創建自託管REST服務& AppHostHttpListenerBase。我想用我的服務基本URI(例如「API」),像這樣:配置ServiceStack基本URI
http://myserver/api/service1/param
http://myserver/api/service2/param
如何做到這一點無需在每個我的路線定義「API」。在IIS中,我可以設置一個虛擬目錄來隔離服務,但如何在自託管時執行此操作?
ServiceStack's HttpListener hosts預計將託管根/路徑,因爲正常使用情況是讓每個自託管服務在不同的自定義端口上可用。
由於它目前不支持在/ custompath中託管,因此您必須在所有服務路由上指定/api/
前綴。
Add an issue如果您想查看自定義路徑的託管支持。
我找到了解決方法。我只在自我託管下測試過。
創建從RouteAttribute
繼承public class PrefixedRouteAttribute : RouteAttribute
{
public static string Prefix { get; set; }
public PrefixedRouteAttribute(string path) :
base(path)
{
SetPrefix();
}
public PrefixedRouteAttribute(string path, string verbs)
: base(path, verbs)
{
SetPrefix();
}
private void SetPrefix()
{
if (!string.IsNullOrWhiteSpace(Prefix))
{
this.Path = string.Format("/{0}{1}", Prefix, Path);
}
}
}
一個「PrefixedRouteAttribute」類當您創建APPHOST你可以設置你的前綴
PrefixedRouteAttribute.Prefix = "api";
然後,而不是使用[路徑]屬性,使用[PrefixRoute]屬性
[PrefixedRoute("/echo")]
[PrefixedRoute("/echo/{Value*}")]
public class Echo
{
[DataMember]
public string Value { get; set; }
}
This wi然後工作請求
/api/echo
/api/echo/1
這可能可以改進。我不太喜歡我需要通過靜態屬性設置前綴,但我無法想象在我的設置下更好的方法。雖然創建重寫屬性的原理聽起來很合理,但這是重要的一部分。
實際上有一個更簡單的解決方案。在你的web.config,更新您的HTTP處理程序:
<httpHandlers>
<add path="api*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" />
</httpHandlers>
通過上述,您的所有服務的API必須用「/ API /」爲前綴。如果您已經在任何路由中使用了「/ api /」,則現在必須刪除它們,或者必須在呼叫中指定兩次。
這裏亞去..(作爲獎勵,這是你如何把你的服務變成一個插件
using BlogEngineService;
using ServiceStack.WebHost.Endpoints;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BlogEngineWinService
{
public class AppHost : AppHostHttpListenerBase
{
public AppHost() : base("Self Host Service", typeof(AppHost).Assembly) { }
public override void Configure(Funq.Container container)
{
Plugins.Add(new BlogEngine());
}
}
}
這是你如何自動裝配起來
電話appHost.Routes.AddFromAssembly2(typeof(HelloService).Assembly);
是什麼叫擴展到汽車線。
using ServiceStack.WebHost.Endpoints;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ServiceStack.ServiceInterface;
namespace BlogEngineService
{
public class BlogEngine : IPlugin, IPreInitPlugin
{
public void Register(IAppHost appHost)
{
appHost.RegisterService<HelloService>();
appHost.Routes.AddFromAssembly2(typeof(HelloService).Assembly);
}
public void Configure(IAppHost appHost)
{
}
}
}
這就是你如何標記服務類給它一個前綴。 只要選中類具有這種屬性
using ServiceStack.DataAnnotations;
using ServiceStack.ServiceHost;
using ServiceStack.ServiceInterface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BlogEngineService
{
public class Hello
{
[PrimaryKey]
public string Bob { get; set; }
}
public class HelloResponse
{
public string Result { get; set; }
}
[PrefixedRoute("/test")]
public class HelloService : Service
{
public object Any(Hello request)
{
return new HelloResponse { Result = "Hello, " + request.Bob};
}
}
}
在項目中創建爲擴展名的文件CS ..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using ServiceStack.Common;
using ServiceStack.Common.Utils;
using ServiceStack.Common.Web;
using ServiceStack.Text;
using ServiceStack.ServiceHost;
using ServiceStack.WebHost.Endpoints;
using ServiceStack.ServiceInterface;
namespace ServiceStack.ServiceInterface
{
public static class ServiceRoutesExtensions
{
/// <summary>
/// Scans the supplied Assemblies to infer REST paths and HTTP verbs.
/// </summary>
///<param name="routes">The <see cref="IServiceRoutes"/> instance.</param>
///<param name="assembliesWithServices">
/// The assemblies with REST services.
/// </param>
/// <returns>The same <see cref="IServiceRoutes"/> instance;
/// never <see langword="null"/>.</returns>
public static IServiceRoutes AddFromAssembly2(this IServiceRoutes routes,
params Assembly[] assembliesWithServices)
{
foreach (Assembly assembly in assembliesWithServices)
{
AddNewApiRoutes(routes, assembly);
}
return routes;
}
private static void AddNewApiRoutes(IServiceRoutes routes, Assembly assembly)
{
var services = assembly.GetExportedTypes()
.Where(t => !t.IsAbstract
&& t.HasInterface(typeof(IService)));
foreach (Type service in services)
{
var allServiceActions = service.GetActions();
foreach (var requestDtoActions in allServiceActions.GroupBy(x => x.GetParameters()[0].ParameterType))
{
var requestType = requestDtoActions.Key;
var hasWildcard = requestDtoActions.Any(x => x.Name.EqualsIgnoreCase(ActionContext.AnyAction));
string allowedVerbs = null; //null == All Routes
if (!hasWildcard)
{
var allowedMethods = new List<string>();
foreach (var action in requestDtoActions)
{
allowedMethods.Add(action.Name.ToUpper());
}
if (allowedMethods.Count == 0) continue;
allowedVerbs = string.Join(" ", allowedMethods.ToArray());
}
if (service.HasAttribute<PrefixedRouteAttribute>())
{
string prefix = "";
PrefixedRouteAttribute a = (PrefixedRouteAttribute)Attribute.GetCustomAttribute(service, typeof(PrefixedRouteAttribute));
if (a.HasPrefix())
{
prefix = a.GetPrefix();
}
routes.AddRoute(requestType, allowedVerbs, prefix);
}
else
{
routes.AddRoute(requestType, allowedVerbs);
}
}
}
}
private static void AddRoute(this IServiceRoutes routes, Type requestType, string allowedVerbs, string prefix = "")
{
var newRoutes = new ServiceStack.ServiceHost.ServiceRoutes();
foreach (var strategy in EndpointHost.Config.RouteNamingConventions)
{
strategy(newRoutes, requestType, allowedVerbs);
}
foreach (var item in newRoutes.RestPaths)
{
string path = item.Path;
if (!string.IsNullOrWhiteSpace(prefix))
{
path = prefix + path;
}
routes.Add(requestType, restPath: path, verbs: allowedVerbs);
}
}
}
public class PrefixedRouteAttribute : Attribute
{
private string _prefix { get; set; }
private bool _hasPrefix { get; set; }
public PrefixedRouteAttribute(string path)
{
if (!string.IsNullOrWhiteSpace(path))
{
this._hasPrefix = true;
this._prefix = path;
//this.Path = string.Format("/{0}{1}", Prefix, Path);
}
}
public bool HasPrefix()
{
return this._hasPrefix;
}
public string GetPrefix()
{
return this._prefix;
}
}
}
不錯的主意......我們最終結束了放棄自託管的IIS提供了更多的高級用例的選項(健康監控,deamonizing等)。 FWIW ...我通過流暢的界面註冊我的路線PrefixedRoute不會工作無副作用AppHostBase ...但仍然,很好的方法和有趣的,簡單的解決方案。 – Fred 2012-11-30 19:08:15