4

サービス スタックと AppHostHttpListenerBase を使用して、セルフホステッド REST サービスを作成しています。次のように、サービス (「api」など) のベース URI を使用したいと思います。

http://myserver/api/service1/param
http://myserver/api/service2/param

各ルートで「api」を定義せずにこれを行うにはどうすればよいですか。IIS では、サービスを分離するために仮想ディレクトリを設定できますが、セルフホスティングの場合はどうすればよいですか?

4

4 に答える 4

4

どうぞ..(おまけとして、これはあなたのサービスをプラグインに入れる方法です.

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;
        }
    }
}
于 2013-05-09T00:41:58.280 に答える
2

ServiceStack の HttpListener ホストは、ルート / パスでホストされることを想定しています。これは、通常のユース ケースでは、各セルフホステッド サービスを異なるカスタム ポートで使用できるようにするためです。

現在、/custompath でのホスティングをサポートしていないため、/api/すべてのサービス ルートでプレフィックスを指定する必要があります。

カスタム パスでのホスティングのサポートが必要な場合は、Issue を追加してください。

于 2012-07-13T19:17:37.213 に答える
2

実はもっと簡単な解決策があります。web.config で、http ハンドラーを次のように更新します。

<httpHandlers>
  <add path="api*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" />
</httpHandlers>

上記では、すべてのサービス API に「/api/」をプレフィックスとして付ける必要があります。いずれかのルートで既に「/api/」を使用している場合は、それらを削除するか、呼び出しで 2 回指定する必要があります。

参考: https ://github.com/ServiceStack/SocialBootstrapApi

于 2013-03-25T16:30:40.810 に答える
1

この回避策を見つけました。私はこれをセルフホスティングでのみテストしました。

RouteAttributeから継承する'PrefixedRouteAttribute'クラスを作成します

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);
    }
  }   
}

AppHostを作成するときに、プレフィックスを設定できます

PrefixedRouteAttribute.Prefix = "api";

次に、[Route]属性を使用する代わりに、クラスで[PrefixRoute]属性を使用します

[PrefixedRoute("/echo")]
[PrefixedRoute("/echo/{Value*}")]
public class Echo
{
  [DataMember]
  public string Value { get; set; }
}

これは、次のリクエストに対して機能します

/api/echo
/api/echo/1

これはおそらく改善される可能性があります。staticプロパティを介してプレフィックスを設定する方法はあまり好きではありませんが、セットアップの下でより良いアプローチを考えることはできませんでした。ただし、オーバーライド属性を作成する原則は正しいように思われますが、それは重要な部分です。

于 2012-11-29T05:48:51.207 に答える