åå ãã代ããã«...
åæ¥èšŒæžãåŠäœè«æã§ã¯ãæåã®ã©ããã§ãåé¡ã¯éåžžå®åŒåãããã¹ãã§ãã ãããã以äžã§èª¬æããããšã¯ããããåé¡ã§ã¯ãããŸããããã¢ããªã±ãŒã·ã§ã³ããã䜿ããããããç§ãã¡ãåãå·»ãäžçãããå°ãçŸããããããšããé¡æã¯ããå°ãçŸããã§ãã ããã¯ãç§ãèªåèªèº«ã«åããããç§ã®äººçã®ç¬éã®1ã€ã§ãã ãããŠãã®åŸãç§ã¯ãããè¡ãæ¹æ³ãèŠã€ããããšããŠããŸãã æã ç§ã¯ãããããŸããæã ç§ã¯ãããæ¹åããããšã¯äžå¯èœã§ããããæçµçã«æå³ããªããªãã»ã©åªåãã䟡å€ãããããšãç解ããŸãã çµå±ããã
ã¿ã¹ã¯ã¹ããŒãã¡ã³ã
ãããããç§ãåããŠããäŒç€Ÿã¯ãè² è·ã®é«ããµã€ãã®éçºã«æºãã£ãŠããŸãã ç§ãçŸåšåãçµãã§ããã¢ããªã±ãŒã·ã§ã³ã®å€§éšåã¯ã顧客ã®å éšAPIã«ã¢ã¯ã»ã¹ããããã®äžçš®ã®æ¿èªããŒã¹ã®ã€ã³ã¿ãŒãã§ãŒã¹ã§ãã ããã«ã¯ããŸãããžãã¯ããªããããã³ããšã³ããšããã¯ãšã³ãã®éã§ã»ãŒçããå²åã§åæ£ãããŠããŸãã äž»èŠãªããžãã¹ããžãã¯ã®ã»ãšãã©ã¯ãããã®APIã«ããããšã³ãã«ã¹ã¿ããŒã«è¡šç€ºããããµã€ãã¯é¡§å®¢ã§ãã
ãµã€ãã«é¢é£ãããµãŒãããŒãã£APIãéåžžã«é·ãæéãŠãŒã¶ãŒã®ãªã¯ãšã¹ãã«å¿çããããšãå€æããå ŽåããããŸãã ããã¯äžæçãªå¹æã§ããå Žåãããã°ãæ°žç¶çãªå ŽåããããŸãã æ¬è³ªçã«ã¢ããªã±ãŒã·ã§ã³ã®è² è·ãé«ãããããŠãŒã¶ãŒãªã¯ãšã¹ããé·æéãµã¹ãã³ãç¶æ ã®ãŸãŸã«ããããšã¯ã§ããŸãããããããªããšããªãŒãã³ãœã±ããã®æ°ãå¢ãç¶ãããµãŒããŒäžã®å¿çã®ãªããªã¯ãšã¹ãã®ãã¥ãŒãæ¥éã«è£å ãããå€æ°ã®ã¯ã©ã€ã¢ã³ããå¿é ããå¯èœæ§ããããŸããããŠããªã圌ãã®ãæ°ã«å ¥ãã®ãµã€ãããããªã«é·ãéããŠããã®ãå¿é ããŠããŸããã APIã§ã¯äœãã§ããŸããã ãã®ç¹ã«é¢ããŠãéåžžã«é·ãæéåããããã©ã³ãµãŒã¯ãªã¯ãšã¹ãã®æéã«5ç§ã«çããå¶éãå°å ¥ããŸããã ããã¯ãã¢ããªã±ãŒã·ã§ã³ã¢ãŒããã¯ãã£ã«äž»ã«å¶éã課ããŸããããã¯ãããã«éåæã®çžäºäœçšãæå³ãããã®çµæãäžèšã®åé¡ã解決ããããã§ãã ãµã€ãèªäœã¯ããã«éãããã§ã«éããŠããããŒãžã§èªã¿èŸŒã¿ã€ã³ãžã±ãŒã¿ãŒãå転ããæçµçã«ãŠãŒã¶ãŒã«äœããã®çµæããããããŸãã ããã¯ãŠãŒã¶ãŒãæåŸ ãããã®ã§ãããããšã©ãŒã¯ãã¯ã倧ããªåœ¹å²ãæãããŸãããããã¯ãŸã£ããç°ãªãã¹ããŒãªãŒã«ãªããŸã...
泚ææ·±ãèªè ã¯æ°ã¥ãã§ãããïŒããããå¶éããã¹ãŠã®ãªã¯ãšã¹ãã«ããå ŽåãAJAXãªã¯ãšã¹ãã«ãé©çšãããŸãã ãã¹ãŠæ£ããã§ãã AJAXãªã¯ãšã¹ããšããã¹ãŠã®ã±ãŒã¹ã§100ïŒ åäœããéåžžã®ããŒãžé·ç§»ãåºå¥ããæ¹æ³ã¯ãŸã£ããããããŸããã ãããã£ãŠãé·ãAJAXãªã¯ãšã¹ãã¯æ¬¡ã®ååã«åŸã£ãŠå®è£ ãããŸãïŒã¯ã©ã€ã¢ã³ããããµãŒããŒã«ãªã¯ãšã¹ããäœæãããµãŒããŒãã¿ã¹ã¯ãäœæããç¹å®ã®GUIDãããã«é¢é£ä»ããŠããããã®GUIDãã¯ã©ã€ã¢ã³ãã«è¿ããã¯ã©ã€ã¢ã³ããAPIãããµãŒããŒã«å°çãããšããã®GUIDã®çµæãåãåããŸãã ãã®æ®µéã§ãç§ã¯
ãããªãŒãã£ã³ã°ã®ããã«ãããã®APIãžã®ãã¹ãŠã®ãªã¯ãšã¹ããšåçãèšé²ããã³ä¿åããå¿ èŠãããããã°ãããã¢ã¯ã·ã§ã³/ã³ã³ãããŒã©ãŒãIPãURIããŠãŒã¶ãŒãã°ã€ã³ãªã©ãšåŒã°ããæçšãªæ å ±ãæ倧éã«åãåãå¿ èŠããããŸãã ãªã© NLogãåããŠäœ¿çšããŠãASP.NET Coreã¢ããªã±ãŒã·ã§ã³ã§èŠæ±/å¿çãä¿è·ãããšããååãšããŠãElasticSearchã§æ¬¡ã®ãããªãã®ã衚瀺ãããŠãé©ããŸããã§ããã
2017-09-23 23:15:53.4287|0|AspNetCoreApp.Services.LongRespondingService|TRACE|/| DoJob method is starting (AspNetCoreApp.Services.LongRespondingService.DoJob:0)| url:http:///
åæã«ãNLogæ§æã§ã¯ãã¹ãŠãéåžžã«ããèŠããã¬ã€ã¢ãŠããšããŠæ¬¡ã®ãã®ãèšå®ãããŸããã
${longdate}|${event-properties:item=EventId.Id}|${logger}|${uppercase:${level}}|${aspnet-mvc-controller}/${aspnet-mvc-action}| ${message} (${callsite}:${callsite-linenumber})| url:${aspnet-request-url}
ããã§ã®åé¡ã¯ãã¯ã©ã€ã¢ã³ããèŠæ±ãå®äºããåŸã«APIããã®å¿çãæ¥ãããšã§ãïŒGUIDã®ã¿ãè¿ããŸãïŒã ãããŠãç§ã¯ãã®åé¡ã®å¯èœãªè§£æ±ºçã«ã€ããŠèãå§ããŸãã...
åé¡ã®å¯èœãªè§£æ±ºç
ãã¡ãããåé¡ã¯ããã€ãã®æ¹æ³ã§ä¿®æ£ã§ããŸãã ãŸããåŸç¹ããããšããç¡èŠããŠã¯ãªããªãããªãã¯ã®1ã€ã§ãã ããããå®éã®ãœãªã¥ãŒã·ã§ã³ãšãã®çµæã«ã€ããŠè©±ããŸãããã
ã¿ã¹ã¯IDãAPIåŒã³åºãã¡ãœããã«æž¡ã
ããã¯ããããé ã«æµ®ãã¶ããšãã§ããæåã®ããšã§ãã GUIDãçæããã¢ã¯ã·ã§ã³ãçµäºããåã«ãã®GUIDããã°ã«èšé²ããAPIãµãŒãã¹ã«æž¡ããŸãã
ãã®ã¢ãããŒãã®åé¡ã¯æããã§ãã ãã®IDãããµãŒãããŒãã£APIã«ã¢ã¯ã»ã¹ãããã¹ãŠã®ã¡ãœããã«çµ¶å¯Ÿã«æž¡ãå¿ èŠããããŸãã åæã«ããã®ãããªæ©èœãå¿ èŠãšããªãä»ã®å Žæã§ãã®éšåãåå©çšãããå Žåãããã¯ç§ãã¡ã倧ãã劚害ããŸãã
ã¯ã©ã€ã¢ã³ãã«ããŒã¿ãæäŸããåã«äœããã®æ¹æ³ã§ããããåŠçãåçŽåããŸãã¯éçŽããå Žåãç¶æ³ã¯æªåããŸãã ããã¯ããžãã¹ããžãã¯ã«åœãŠã¯ãŸããå¥ã®éšåã§åãåºãå¿ èŠããããŸãã å¯èœãªéãç¬ç«ãããŸãŸã«ããå¿ èŠã®ãããã®éšåã¯ããã®èå¥åã§ãæ©èœããããšãããããŸããïŒ ãããã£ãŠãç©äºã¯å®äºããŠããªãã®ã§ãä»ã®æ¹æ³ãæ€èšããŠãã ããã
CallContextã«ã¿ã¹ã¯IDãä¿åãã
ãã¬ãŒã ã¯ãŒã¯ããããã®ç®çã®ããã«æäŸããããŒã«ã«ã€ããŠèããå Žåãæåã«èŠããŠããã¹ãããšã¯ãLogicalSetData / LogicalGetDataãæã€CallContextã§ãã ãããã®ã¡ãœããã䜿çšãããšãCallContext'eã«ã¿ã¹ã¯IDãä¿åã§ããŸãã.NETïŒã€ãŸã.NET 4.5ïŒã¯ãæ°ããã¹ã¬ãããèªåçã«åãããŒã¿ã«ã¢ã¯ã»ã¹ããããã«æ³šæããŸãã ãã¬ãŒã ã¯ãŒã¯å ã§ã¯ãããã¯Mementoã«äŒŒããã¿ãŒã³ã䜿çšããŠå®è£ ãããæ°ããã¹ã¬ãã/ã¿ã¹ã¯ãéå§ããããã®ãã¹ãŠã®ã¡ãœããã§äœ¿çšããå¿ èŠããããŸãã
// snapshot var ec = ExecutionContext.Capture(); ... // snapshot ExecutionContext.Run(ec, obj => { // snapshot , }, state);
IDãä¿åããŠã¿ã¹ã¯ã«ååŸããæ¹æ³ãããã£ãã®ã§ããã°ã«èšé²ãããåã¡ãã»ãŒãžã«ãã®èå¥åãå«ããããšãã§ããŸãã ãããè¡ãã«ã¯ããã®ã³ã°ã¡ãœãããåŒã³åºããŸãã ãŸãã¯ãããŒã¿ã¢ã¯ã»ã¹å±€ãè©°ãŸãããªãããã«ããã¬ãŒã®æ©èœã䜿çšã§ããŸãã ããšãã°ãNLogã«ã¯Layout RenderersããããŸãã
ãŸããæåŸã®æ段ãšããŠãç¬èªã®ãã¬ãŒãäœæã§ããŸãã ASP.NET Coreã§ã¯ããã¹ãŠã®ãã®ã³ã°ã¯ãMicrosoft.Extensions.Loggingåå空éã«ããç¹å¥ãªã€ã³ã¿ãŒãã§ã€ã¹ã䜿çšããŠè¡ãããŸããããã¯ãDIãä»ããŠã¯ã©ã¹ã«å®è£ ãããŸãã ãããã£ãŠãILoggerãšILoggerProviderã®2ã€ã®ã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ããã ãã§ååã§ãã ãã®ãªãã·ã§ã³ã¯ããã¬ãŒãæ¡åŒµæ©èœããµããŒãããŠããªãå Žåã«åœ¹ç«ã€ãšæããŸãã
ãããŠããã¹ãŠãæ£åžžã«æ©èœããããã«ã Stephen Clearyã®èšäºãèªãããšããå§ãããŸãã .NET Coreãžã®ãã€ã³ãã¯ãããŸããïŒ2013幎ã«ã¯ããŸã ååšããŠããŸããã§ããïŒããããã«åœ¹ç«ã€äœããæ確ã«åŒ·èª¿ã§ããŸãã
ãã®ã¢ãããŒãã®æ¬ ç¹ã¯ãèå¥åãæã€ã¡ãã»ãŒãžããã°ã«èšé²ããããããå šäœåãææ¡ããã«ã¯ãåãIDãæã€HTTPãªã¯ãšã¹ããæ¢ãå¿ èŠãããããšã§ãã ããã©ãŒãã³ã¹ã«ã€ããŠã¯äœãèšããŸããããªããªããäœããã®ãããŒããŠã³ããã£ãŠããä»ã®ãã®ãšæ¯èŒãããšãããã¯äžé£ãåãã«å°ããªå€ã«èŠããããã§ãã
ãããããªããããæ©èœããªãã®ããèãããã©ãã§ããããïŒ
ãã§ã«è¿°ã¹ãããã«ã次ã®ãããªã¡ãã»ãŒãžããããŸãã
2017-09-23 23:15:53.4287|0|AspNetCoreApp.Services.LongRespondingService|TRACE|/| DoJob method is starting (AspNetCoreApp.Services.LongRespondingService.DoJob:0)| url:http:///
ããªãã¡ IHttpContextã«é¢é£ãããã®ã¯ãã¹ãŠåçŽã«ç¡å¹åãããŸãã ç解ã§ããããã§ãïŒã¯ãšãªãçµäºãããããNLogã¯ããŒã¿ãåä¿¡ã§ããŸããã HttpContextãžã®ãªã³ã¯ã¯ãªããªããŸããã
æåŸã«ãNLogãå®éã«ã³ã³ãããŒã©ãŒå€éšã®HttpContextãžã®ãªã³ã¯ãååŸããæ¹æ³ã確èªããããšã«ããŸããã .NET Coreã®SynchronizationContextãšHttpContext.Current ãçµãã£ãã®ã§ïŒã¯ãããããStephen Clearyã§ãïŒããããè¡ãä»ã®æ¹æ³ãå¿ èŠã§ãã
![ç»å](https://habrastorage.org/getpro/habr/post_images/c80/363/eb3/c80363eb3a2c7f0ce050e339a988e1ac.png)
NLogãœãŒã¹ã³ãŒããæãäžããŠã¿ããš ãç¹å®ã®IHttpContextAccessorãèŠã€ãããŸããã ããã§äœãèµ·ãã£ãŠããã®ããç解ããã®ãæžããã®ã§ãGitHubã«åã³ç»ãã1ã€ã®ããããã£ãæã€ãã®éæ³ã®ãããªãã®ãäœã§ãããã確èªããŸããã ããã¯ãæ¬è³ªçã«LogicalCallContextã®æ°ããããŒãžã§ã³ïŒLogicalSetData / LogicalGetDataã®ã¡ãœããïŒã§ããAsyncLocalã®åãªãæœè±¡åã§ããããšãå€æããŸããã ã¡ãªã¿ã«ãããã¯.NET Frameworkã®å Žåã¯åžžã«ããã§ã¯ãããŸããã§ãã ã
ãã®åŸãç§ã¯èªåèªèº«ã«è³ªåãããŸããïŒãªããå®éã«æ©èœããªãã®ã§ããïŒ ã¿ã¹ã¯ãæšæºçãªæ¹æ³ã§å®è¡ããŸããããã«ã¯ã¢ã³ãããŒãžã³ãŒãã¯ãããŸãã...ãã®ã³ã°ã¡ãœãããåŒã³åºããããšãã«HttpContextã§äœãèµ·ãããã確èªããããã«ãããã¬ãŒãå®è¡ããŸããHttpContextã¯ãããŸãããRequest.Schemeãé€ããã¹ãŠã®ããããã£ã¯çŸåšãªã»ãããããŠããŸãåŒã³åºãã¯ãhttpãã§ãã ãã®ããããã°ã«ã¯å¥åŠãªã
http:///
ããurlã®ä»£ããã«ãããŸãã
ãã®ãããããã©ãŒãã³ã¹ãåäžãããããã«ãASP.NET CoreèªäœãHttpContextããªã»ããããŠåå©çšããããšãããããŸããã ã©ãããããã®ãããªåŸ®åŠãªç¹ãçµã³ã€ããå€ãASP.NET MVCã«æ¯ã¹ãŠå€§ããªå©ç¹ãéæã§ããããã«ãªã£ãŠããŸãã
ç§ã¯ããã«ã€ããŠäœãã§ããŸããïŒ ã¯ããHttpContextã®çŸåšã®ç¶æ ãä¿åããã ãã§ãïŒ DIã³ã³ãããŒã«ç»é²ããå¯äžã®CloneCurrentContextã¡ãœããã䜿çšããŠåçŽãªãµãŒãã¹ãäœæããŸããã
HttpContextPreserver
public class HttpContextPreserver : IHttpContextPreserver { private readonly IHttpContextAccessor _httpContextAccessor; ILogger _logger; public HttpContextPreserver(IHttpContextAccessor httpContextAccessor, ILogger<HttpContextPreserver> logger) { _httpContextAccessor = httpContextAccessor; _logger = logger; } public void CloneCurrentContext() { var httpContext = _httpContextAccessor.HttpContext; var feature = httpContext.Features.Get<IHttpRequestFeature>(); feature = new HttpRequestFeature() { Scheme = feature.Scheme, Body = feature.Body, Headers = new HeaderDictionary(feature.Headers.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)), Method = feature.Method, Path = feature.Path, PathBase = feature.PathBase, Protocol = feature.Protocol, QueryString = feature.QueryString, RawTarget = feature.RawTarget }; var itemsFeature = httpContext.Features.Get<IItemsFeature>(); itemsFeature = new ItemsFeature() { Items = itemsFeature?.Items.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) }; var routingFeature = httpContext.Features.Get<IRoutingFeature>(); routingFeature = new RoutingFeature() { RouteData = routingFeature.RouteData }; var connectionFeature = httpContext.Features.Get<IHttpConnectionFeature>(); connectionFeature = new HttpConnectionFeature() { ConnectionId = connectionFeature?.ConnectionId, LocalIpAddress = connectionFeature?.LocalIpAddress, RemoteIpAddress = connectionFeature?.RemoteIpAddress, }; var collection = new FeatureCollection(); collection.Set(feature); collection.Set(itemsFeature); collection.Set(connectionFeature); collection.Set(routingFeature); var newContext = new DefaultHttpContext(collection); _httpContextAccessor.HttpContext = newContext; } } public interface IHttpContextPreserver { void CloneCurrentContext(); }
ãã£ãŒãã¯ããŒã³ã䜿çšããªãã£ãã®ã¯ããããžã§ã¯ãã«å€§ããªåçãå ããããã§ãã ãããŠãç§ã¯ããããã äžã€ã®å Žæã§å¿ èŠãšããŸãã ãããã£ãŠãæ¢åã®ãã®ã«åºã¥ããŠæ°ããHttpContextãäœæããã€ã³ã·ãã³ãïŒã¢ã¯ã·ã§ã³|ã³ã³ãããŒã©ãŒãURLãIPãªã©ïŒãåæãããšãã«ãã°ã«è¡šç€ºããã®ã«æçšãªãã®ã®ã¿ãã³ããŒããŸãã ãã¹ãŠã®æ å ±ãã³ããŒãããããã§ã¯ãããŸãã ã
ã¢ããªã±ãŒã·ã§ã³ãéå§ãããšã次ã®å¹žããªè¡ãèŠãŸããã
2017-10-08 20:29:25.3015|0|AspNetCoreApp.Services.LongRespondingService|TRACE|Home/Test| DoJob method is starting (AspNetCoreApp.Services.LongRespondingService.DoJob:0)| url:http://localhost/Test/1 2017-10-08 20:29:34.3322|0|AspNetCoreApp.Services.LongRespondingService|TRACE|Home/Test| DoJob method is ending (AspNetCoreApp.Services.LongRespondingService+<DoJob>d__3.MoveNext:0)| url:http://localhost/Test/1
ãããŠãããã¯ç§ã«ãšã£ãŠå°ããªåå©ãæå³ããŸããã 誰ãããã«ã€ããŠèããŠããŸããïŒ
èªåã«ééã£ãããšãèããªãããã«ããããã«ãå°ããªæ©èœè² è·ãã¹ããäœæããŸãããããã¯ããµãŒãã¹ãšãšãã«githubãªããžããªã§èŠã€ããããšãã§ããŸãã 5000ã®åæã¿ã¹ã¯ãéå§ãããšããã¹ãã¯æåããŸããã
![ç»å](https://habrastorage.org/getpro/habr/post_images/f6f/33e/f1e/f6f33ef1e013d8d322339500fe098184.png)
ãšããã§ãASP.NET Coreã®ã¢ãŒããã¯ãã£ã®ãããã§ããã®ãããªãã¹ãã¯ç°¡åãã€èªç¶ã«äœæã§ããŸãã ãã¹ãå ã§ãµãŒããŒå šäœãå®è¡ããå®éã®ãœã±ãããä»ããŠã¢ã¯ã»ã¹ããã ãã§ãã
URLã«ãããµãŒããŒã®åæå
protected TestFixture(bool fixHttpContext, string solutionRelativeTargetProjectParentDir) { var startupAssembly = typeof(TStartup).Assembly; var contentRoot = GetProjectPath(solutionRelativeTargetProjectParentDir, startupAssembly); Console.WriteLine($"Content root: {contentRoot}"); var builder = new WebHostBuilder() .UseKestrel() .UseContentRoot(contentRoot) .ConfigureServices(InitializeServices) .UseEnvironment(fixHttpContext ? "Good" : "Bad") .UseStartup(typeof(TStartup)) .UseUrls(BaseAddress); _host = builder.Build(); _host.Start(); }
ãããžã§ã¯ãã§ASP.NET Coreã䜿çšãããã1ã€ã®çç±ã
ãŸãšã
å®è£ ã®ãã¹ãŠã®é¢ã§ASP.NET Coreãæ¬åœã«å¥œãã§ããã åªããæè»æ§ãšããã©ãããã©ãŒã å šäœã®è»œããå ŒãåããŠããŸãã 絶察ã«ãã¹ãŠã®æ©èœãæœè±¡åãããŠãããããèªåèªèº«ãããŒã ãããã³éçºæ¹æ³ã«åãããŠããããããšãå®è¡ãããã©ãããã©ãŒã å šäœãã«ã¹ã¿ãã€ãºã§ããŸãã ã¯ãã¹ãã©ãããã©ãŒã ã¯ãŸã å®æããŠããŸããããMicrosoftã¯ãããç®æããŠåªåããŠããããã€ã®æ¥ãïŒããã§ã¯ãªããããããŸãããïŒæåããã¯ãã§ãã
Githubãªã³ã¯