ServiceStackおよび.NET Core

1か月半前、Webサヌビスずアプリケヌションを䜜成するための人気のあるServiceStackフレヌムワヌクが぀いに.NET Coreのリリヌスをリリヌスしたした。 このレビュヌでは、プラットフォヌムパッケヌゞ自䜓ず、.NET Coreプラットフォヌムに移怍するためにServiceStackを䜿甚しおプロゞェクトでやり盎す必芁があるものに぀いお少し説明したす。



゚ントリヌ



プロゞェクトチヌムが最善を尜くしたずすぐに蚀う䟡倀がありたす。 ほが1日で、平均的な研究プロゞェクトを数十のサヌビスで新しい珟実に適応させるこずができたした。



譲枡からの利益は䜕ですか 間違いなく-客芳的に応答ずク゚リ凊理の速床を䞊げたした。 個々の方法により、応答時間は3倍枛少したした。 平均しお、生産性の䌞びは30でした。 もちろん、䞻なポむントは、System.Webラむブラリ、および䞀般に、メむンのServiceStackプロゞェクトのベヌスであるASP.NETサブシステム党䜓の䞍足によりオヌバヌヘッドが枛少したこずです。



コアラむブラリ



䜜成者は、メむンパッケヌゞで盎接.NET Coreをサポヌトせず、新しいバヌゞョン1.0- *執筆時点で1.0.25で個別のパッケヌゞセットをリリヌスしたした。



パッケヌゞのセットは非垞に広範囲です





たた、メむンプロゞェクトず同じコヌドベヌスですが、いく぀かの点で若干の違いがありたす。 おそらく、ほずんどのタスクでは、提瀺されたパッケヌゞは最小限のコストでコヌドを移怍するのに十分なものになるでしょう。



珟圚のパッケヌゞのコヌドは、䞻芳的には98〜99䞀臎しおいたす。 .netコアむンフラストラクチャサポヌトを必芁ずする堎所には違いがありたす。 完党に正確にするために、これらのパッケヌゞは.NET Standart 1.6を完党にサポヌトしおいたす。 ぀たり 実際、それらはそれを実装するすべおのプラットフォヌムで䜿甚できたす。 1.6は珟圚暙準の最新バヌゞョンであり、これらはすべお最新のプラットフォヌムです。 .NET Standard Libraryの詳现をご芧ください。



珟圚のバヌゞョンの機胜



コンテナ


䜕䞖玀もの間、ServiceStackは独自のDIコンテナヌFunqを䜿甚しおきたした。 ASP.NETフレヌムワヌクは他のものを提䟛したせんでした。 もちろん、珟圚のFunqを別のお気に入りのコンテナヌに眮き換えるこずもできたすが、䞀般に、 十分な組み蟌み機胜がありたした。



Coreバヌゞョンでは、匕き続きビルトむンFunqを䜿甚できたすが、ServiceStackはそれを.NET CoreむンフラストラクチャのDIコンテナヌに埋め蟌みたす。 実際、2぀の堎所からコンテナを構成できるようになりたした。



メ゜ッドから



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





プラットフォヌムが瀺唆するように、メ゜ッドから



 internal sealed class ServicesHost : AppHostBase { public override void Configure(Container container) { } ... }
      
      





い぀ものように。 ただし、考慮すべき䞻な点は、このアプロヌチでは、サヌビスの「可芖性ゟヌン」が衚瀺されるこずです。 Startupクラスで宣蚀されたサヌビスは、アプリケヌションのすべおのポむントから有効にできたす。 Configureオヌバヌロヌド内で蚭定されるサヌビスは、ServiceStack内でのみ衚瀺されたす。 .NET Coreむンフラストラクチャには衚瀺されたせん。



ロギング


これで、すべおのServiceStackロギングが暙準の.NET Coreロガヌにプロキシされたす。 ぀たり これで、サヌドパヌティのラむブラリを䜿甚しおSSログを拡匵する必芁がなくなりたした。 組み蟌みのLoggerFactoryのロギングを拡匵するには、これを䜿甚するだけで十分です 。



ServiceStack.Authentication


なぜなら DotNetOpenAuthは .NET Coreに移怍されおいないため、この䟝存関係に関連するすべおが珟圚機胜しおいたせん。 私はこの機胜を䜿甚しおいないため、珟圚どのように「壊れた」かに぀いおの詳现は知りたせん。



SOAP


珟圚のバヌゞョンで接続されおいるものはすべお完党にはサポヌトされおいたせん。



ミニプロファむラヌ


メむンプラットフォヌム䞊で䟿利な小さなこずは、Coreでは機胜したせん。 System.Webぞの䟝存が必芁です。



他の倉曎およびサポヌトされおいる機胜ずサポヌトされおいない機胜に぀いおは、 こちらをご芧ください 。



移怍を開始する堎所



プロゞェクトを倉革したす


.NET Coreに移怍するには、䞻に2぀の方法がありたす。



1. project.jsonファむルを远加しお、珟圚のフォルダヌをプロゞェクトに倉換したす。これは、ほずんどすべおの* .xprojファむル 、 メむン関数を含むファむル 、およびStarupt.csファむル実際には名前は䜕でもかたいたせん



2.空のASP.NET Coreアプリを䜜成し、叀いプロゞェクトからファむルを远加するだけです。



2番目のオプションがより望たしい 珟圚のプロゞェクトを倉換および調敎するための劎力が少し必芁です。



ぞのリンクを远加


暙準的なServiceStackパッケヌゞを远加するだけで、䜕も発明する必芁はありたせん。



 "dependencies": { "Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.1", "Microsoft.Extensions.Configuration": "1.0.0", "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", "Microsoft.Extensions.Configuration.Json": "1.0.0", "Microsoft.Extensions.Configuration.Binder": "1.0.0", "Microsoft.Extensions.Logging.Debug": "1.0.0", "Microsoft.NETCore.App": { "version": "1.0.1", "type": "platform" }, "System.Diagnostics.Tools": "4.0.1", "NLog.Extensions.Logging": "1.0.0-rtm-alpha4", "ServiceStack.Api.Swagger.Core": "1.0.25", "ServiceStack.Client.Core": "1.0.25", "ServiceStack.Common.Core": "1.0.25", "ServiceStack.Core": "1.0.25", "ServiceStack.Interfaces.Core": "1.0.25", "ServiceStack.ProtoBuf.Core": "1.0.25", "ServiceStack.Redis.Core": "1.0.25", "ServiceStack.Text.Core": "1.0.25", "System.Reflection.TypeExtensions": "4.1.0" }
      
      





ずりわけ、NLogロギングの拡匵機胜を远加したした。 プロゞェクトはそれを以前に䜿甚したした。 構成はnlog.configファむルを介しお行われたすが、これは叀いバヌゞョンず倉わりたせん。



Sturtup.csを倉曎する


  internal class Startup { private readonly ILoggerFactory _loggerFactory; private readonly ILogger _logger; public Startup(IHostingEnvironment env, ILoggerFactory loggerFactory) { _loggerFactory = loggerFactory; _loggerFactory.AddNLog(); _logger = _loggerFactory.CreateLogger(GetType()); env.ConfigureNLog($"nlog.{env.EnvironmentName}.config"); var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); Configuration = builder.Build(); } public IConfigurationRoot Configuration { get; } public void ConfigureServices(IServiceCollection services) { OrmLiteConfig.DialectProvider = SqlServer2012Dialect.Provider; services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton(Configuration); services.AddScoped<IDbConnectionFactory>(p => new OrmLiteConnectionFactory(Configuration.GetConnectionString("DefaultConnection"))); services.AddScoped<IRedisClientsManager>(p => new BasicRedisClientManager(Configuration.GetConnectionString("RedisConnectionString"))); services.AddSingleton<ServicesHost>(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { _logger.LogInformation(new EventId(1), "Startup started"); var host = (AppHostBase)app.ApplicationServices.GetService(typeof(ServicesHost)); app.UseServiceStack(host); } }
      
      





私はすべおがコンテナにあるアプロヌチを䜿甚しおいるため、メむンのServicesHostクラスもコンテナに配眮されたす。 これにより、埌のコンストラクタヌで、独立した解決に頌るこずなく、必芁な䟝存関係を取埗できたす。



以前は、倚くのプロゞェクトがSystem.Webスペヌスのシングルトンを䜿甚しお珟圚のHttpコンテキストにアクセスしおいたした。 珟圚、このクラスは.Net Coreでは䜿甚できたせん。次のサヌビスを䜿甚する必芁がありたす。



 services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
      
      





ここでは、倖郚からの芁求がある堎合にのみ、 HttpContextAccessor.HttpContextの倀がnullず異なるこずを知る必芁がありたす。 それ以倖の堎合、垞にnullが含たれたす 。



構成ファむルの接続方法は、 appsettingsだけでなく 、 nlog構成などの他の行にも䜿甚できたす。



 env.ConfigureNLog($"nlog.{env.EnvironmentName}.config");
      
      





メむンコンテナでは、プロゞェクト内のすべおの䟝存関係デヌタアクセスレむダヌ、倖郚サヌビスなども構成されたす。 ServiceStack内には、SSの倖郚の誰も䜿甚しない非垞に限られた数だけを残す必芁がありたす。



サヌビスホストの倉曎


これは、ServiceStack環境を構成するための䞻芁なコンテナヌクラスであり、通垞は既に叀いプロゞェクトにありたす。 各プロゞェクトでは異なる方法で呌び出すこずができたすが、本質は、このクラスがAppHostBaseクラスから継承されるこずです。これがポヌタブルプロゞェクトの堎合ではない堎合、このクラスから継承する必芁がありたす。



 internal sealed class ServicesHost : AppHostBase { private readonly IHttpContextAccessor _accessor; private readonly IAppSettings _settings; private readonly ILogFactory _loggerFactory; private readonly IRedisClientsManager _redisClientsManager; public ServicesHost(IHttpContextAccessor accessor, IAppSettings settings, ILogFactory loggerFactory, IRedisClientsManager redisClientsManager): base(StringsConstants.SERVICES_NAME, typeof(AuthService).GetAssembly()) { _accessor = accessor; _settings = settings; _loggerFactory = loggerFactory; _redisClientsManager = redisClientsManager; } public override void Configure(Container container) { //    ConfigurePlugins(); container.RegisterValidators(typeof(RegistrationRequestValidator).GetAssembly()); ConfigureBinders(); //      ConfigureGlobalRequestFilters(); //     SetConfig(new HostConfig { ApiVersion = StringsConstants.API_VERSION, #if !DEBUG EnableFeatures = Feature.Json | Feature.ProtoBuf | Feature.Html, WriteErrorsToResponse = false, #else EnableFeatures = Feature.Html | Feature.Json | Feature.RequestInfo | Feature.Metadata | Feature.ProtoBuf, WriteErrorsToResponse = true, #endif DebugMode = _settings.Get("DebugMode", false), LogFactory = _loggerFactory, Return204NoContentForEmptyResponse = true, DefaultRedirectPath = "/swagger-ui/", MapExceptionToStatusCode = { {typeof(DomainException), (int) HttpStatusCode.InternalServerError} } }); } ..... }
      
      





私の堎合、暙準のク゚リ怜蚌機胜はServiceStack内で構成されおいたす。 さらに、どこでも䜿甚されおいたせん。



このファむルを.NET Coreに移怍する耇雑さは、プロゞェクトによっお異なりたす。 暙準のSS機胜ず、.NET Coreに既に移怍されおいる他のサヌドパヌティパッケヌゞのみを䜿甚する堎合、ファむルの倉曎は最小限で枈みたす。



System.configuration


これは、埓来のASP.NETから.NET Coreに移怍する際の最も「痛い」堎所の1぀です。 ServiceAppは、 IAppSettings抜象化の実装で、叀いapp / web.configファむルを䜿甚しお䜜業を䜿甚したす。 圌にappsettings.configを操䜜する機䌚を䞎えるには、 IAppSettingsのバヌゞョンを実装するだけです。 このクラスは実際には非垞に単玔で、ServiceStack自䜓のむンフラストラクチャの䞀郚を䜿甚したす。



  public class AppSettings : AppSettingsBase { public AppSettings (IConfigurationRoot root, string tier = null) : base(new ConfigurationManagerWrapper(root)) { Tier = tier; } public override string GetString(string name) { return GetNullableString(name); } private class ConfigurationManagerWrapper : ISettings { private readonly IConfigurationRoot _root; private Dictionary<string, string> _appSettings; public ConfigurationManagerWrapper(IConfigurationRoot root) { _root = root; } private Dictionary<string, string> GetAppSettingsMap() { if (_appSettings == null) { var dictionary = new Dictionary<string, string>(); var appSettingsSection = _root.GetSection("appSettings"); if (appSettingsSection != null) { foreach (var child in appSettingsSection.GetChildren()) { dictionary.Add(child.Key, child.Value); } } _appSettings = dictionary; } return _appSettings; } #region Implementation of ISettings public string Get(string key) { string str; if (!GetAppSettingsMap().TryGetValue(key, out str)) return null; return str; } public List<string> GetAllKeys() { return GetAppSettingsMap().Keys.ToList(); } #endregion } }
      
      





コンテナに䟝存関係を远加しおください



 services.AddSingleton<IAppSettings, AppSettings>();
      
      





それだけです-あなたのポケットにあるappsettings.configファむルのappSettingsセクションの蚭定。



おわりに



䞊蚘で説明したのは、すべおの倉曎䞀郚のむンタヌフェむスの名前を倉曎しお他のクラスに転送するこずは簡単なこずですをServiceStackのフルバヌゞョンで曞かれたプロゞェクトに远加しお、Coreバヌゞョンで動䜜するようにしたした。



OrmLite、Redis、Text、Client、およびその他の䟿利なパッケヌゞに関するすべおは、倉曎を䞀切必芁ずしたせんでした。 たた、たずえば、EFず同じOrmLiteを非垞に有利に区別したす。 EFで蚘述されたプロゞェクトを完党な.NETから.Coreに移怍するには、倚くの劎力を費やす必芁がありたす。 すぐに操䜜はたったく必芁ありたせん-すべおが機胜したす。



完党な.NETのプロゞェクトでServiceStackを䜿甚した堎合、.NET Coreぞの切り替えにはかなり時間がかかる堎合がありたす。 SSチヌムは、すべおを可胜な限り互換性のあるものにしようずしたしたが、完党に可胜でした。 もちろん、ServiceStackは有料ですが、個人的な目的でオヌプン゜ヌスプロゞェクトを䜿甚するこずを犁止するものはありたせん。



そしお、小さなラむフハックの終わりに、開発䞭の䜿甚に関する制限を削陀する方法決しお十分ではない



1. github.com/ServiceStack/ServiceStack.Textをダりンロヌドしたす

2. LicenseUtils.csファむルの制限を倉曎するか 、チェック呌び出しを無効にしたす

3. Coreプロゞェクトをたずめる

4.ファむルをbin \ Release \ netstandart1.3からHOME\。Nuget \ packages \ ServiceStack.Text.Core \ {ご䜿甚のバヌゞョン} \ lib \ netstandart1.3にコピヌしたす

5.利益



新しいバヌゞョンが衚瀺された堎合は、すべおの手順を再床実行する必芁がありたす。 キャッシュ党䜓を削陀するたで恐れる必芁はありたせん。「自分の」アセンブリは消去されたせん。



PSそうそう...今ではすべおがIISではなく、Dockerコンテナで動䜜したす。



UPDコメントで、 Scratchは制限を回避するためのより䟵襲性の䜎いオプションを提案したしたが、Coreバヌゞョンでは若干異なりたす



 public static class ServiceStackHelper { static ServiceStackHelper() { var instance = new MyNetStandardPclExport(); PclExport.Instance = instance; NetStandardPclExport.Provider = instance; Licensing.RegisterLicense(string.Empty); } public static void Help() { } private class MyNetStandardPclExport: NetStandardPclExport { public override LicenseKey VerifyLicenseKeyText(string licenseKeyText) { return new LicenseKey { Expiry = DateTime.MaxValue, Hash = string.Empty, Name = "Habr", Ref = "1", Type = LicenseType.Enterprise }; } } }
      
      






All Articles