{"id":9019,"date":"2024-02-06T17:04:53","date_gmt":"2024-02-06T08:04:53","guid":{"rendered":"https:\/\/www.auctionpro.co.kr\/?p=9019"},"modified":"2024-03-14T08:45:23","modified_gmt":"2024-03-13T23:45:23","slug":"netcore","status":"publish","type":"post","link":"https:\/\/www.auctionpro.co.kr\/?p=9019","title":{"rendered":"NetCore6.0  Memory Cache (Web XML Data)"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">1. Memory Cache Simple sample<\/h2>\n\n\n\n<figure class=\"wp-block-embed is-type-wp-embed is-provider-auctionpro wp-block-embed-auctionpro\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"nQw3Ny92gZ\"><a href=\"https:\/\/www.auctionpro.co.kr\/?p=9064\">NetCore6.0 Memory Cache simple<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; clip: rect(1px, 1px, 1px, 1px);\" title=\"&#8220;NetCore6.0 Memory Cache simple&#8221; &#8212; AuctionPro\" src=\"https:\/\/www.auctionpro.co.kr\/?p=9064&#038;embed=true#?secret=KemA91LAIs#?secret=nQw3Ny92gZ\" data-secret=\"nQw3Ny92gZ\" width=\"500\" height=\"282\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">2. Memory Cache Interface sample (web XML Data)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>xml \ub370\uc774\ud0c0 : https:\/\/auctionpro.co.kr\/airlinecode.xml<\/li>\n\n\n\n<li> xml \ub370\uc774\ud0c0 \uc774\uc6a9\ud55c  \uba54\ubaa8\ub9ac \uce90\uc2f1 \uc0d8\ud514<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Web XML Data<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/02\/image-10.png\"><img loading=\"lazy\" decoding=\"async\" width=\"488\" height=\"750\" src=\"https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/02\/image-10.png\" alt=\"\" class=\"wp-image-9082\" srcset=\"https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/02\/image-10.png 488w, https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/02\/image-10-195x300.png 195w\" sizes=\"auto, (max-width: 488px) 100vw, 488px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">UML<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/02\/image-18.png\"><img loading=\"lazy\" decoding=\"async\" width=\"920\" height=\"523\" src=\"https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/02\/image-18.png\" alt=\"\" class=\"wp-image-9111\" srcset=\"https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/02\/image-18.png 920w, https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/02\/image-18-300x171.png 300w, https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/02\/image-18-768x437.png 768w\" sizes=\"auto, (max-width: 920px) 100vw, 920px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/03\/image-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1322\" height=\"643\" src=\"https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/03\/image-3.png\" alt=\"\" class=\"wp-image-9129\" srcset=\"https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/03\/image-3.png 1322w, https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/03\/image-3-300x146.png 300w, https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/03\/image-3-1024x498.png 1024w, https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/03\/image-3-768x374.png 768w\" sizes=\"auto, (max-width: 1322px) 100vw, 1322px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Program Files<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/02\/image-4.png\"><img loading=\"lazy\" decoding=\"async\" width=\"392\" height=\"397\" src=\"https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/02\/image-4.png\" alt=\"\" class=\"wp-image-9055\" srcset=\"https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/02\/image-4.png 392w, https:\/\/www.auctionpro.co.kr\/wp-content\/uploads\/2024\/02\/image-4-296x300.png 296w\" sizes=\"auto, (max-width: 392px) 100vw, 392px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">AirlineController<\/h3>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:c# decode:true \" title=\"AirlineController\">using Microsoft.AspNetCore.Mvc;\nusing InMemoryCacheCore.Models;\nusing InMemoryCacheCore.Services;\n\nnamespace InMemoryCacheCore.Controllers\n{\n    [ApiController]\n    [Route(\"[controller]\")]\n    public class AirlineController : ControllerBase\n    {\n        private readonly ICodeService _codeService;\n        private readonly ICacheService _cacheService;\n\n        private readonly ILogger&lt;AirlineController&gt; _logger;\n\n        public AirlineController(ICodeService codeService, ICacheService cacheService, ILogger&lt;AirlineController&gt; logger)\n        {\n            _codeService = codeService ?? throw new ArgumentNullException(nameof(codeService));\n            _cacheService = cacheService ?? throw new ArgumentNullException(nameof(cacheService));\n            _logger = logger;\n        }\n\n        [HttpGet(Name = \"AirlineCode\")]\n        public async Task&lt;IEnumerable&lt;Code&gt;&gt; Get()\n        {\n            try\n            {\n                IEnumerable&lt;Code&gt; codes = _cacheService.GetCachedCode(\"_Codes\");\n\n                if (codes == null || !codes.Any())\n                {\n                    codes = await _codeService.GetCodeAsync();\n                }\n\n                return codes ?? new List&lt;Code&gt;();\n\n                \/\/codes = codes.Where(s =&gt; s.Airlinecode.Equals(\"KE\", StringComparison.Ordinal)) ?? new List&lt;Code&gt;();\n                \/\/return codes;\n\n            }\n            catch (Exception ex)\n            {\n                _logger.LogError(ex, \"\uc815\ubcf4\ub97c \uac00\uc838\uc624\ub294 \ub3d9\uc548 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.\");\n                throw;\n            }\n\n        }\n\n\n    }\n}\n<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">AirlineHttpClient<\/h3>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:c# decode:true \" title=\"AirlineHttpClient\">using InMemoryCacheCore.Models;\nusing System.Xml.Serialization;\n\nnamespace InMemoryCacheCore.Infrastructure\n{\n    public interface IHttpClient\n    {\n        Task&lt;IEnumerable&lt;Code&gt;&gt; Get();\n    }\n\n    public class AirlineHttpClient : IHttpClient\n    {\n        private const string API_URL = \"https:\/\/auctionpro.co.kr\/airlinecode.xml\";\n\n        private readonly HttpClient _httpClient;\n\n        public AirlineHttpClient(HttpClient httpClient)\n        {\n            _httpClient = httpClient;\n        }\n\n        public async Task&lt;IEnumerable&lt;Code&gt;&gt; Get()\n        {\n            HttpResponseMessage response = await _httpClient.GetAsync(API_URL);\n\n            if (response.IsSuccessStatusCode)\n            {\n                await using var responseStream = await response.Content.ReadAsStreamAsync();\n\n                var serializer = new XmlSerializer(typeof(Root));\n                var codesResponse = serializer.Deserialize(responseStream) as Root;\n\n                var codes = codesResponse?.Code ?? new List&lt;Code&gt;();\n\n                return codes;\n            }\n            else\n            {\n                \/\/ \uc608\uc678 \uba54\uc2dc\uc9c0\uc5d0 \uc2e4\ud328 \uc6d0\uc778 \ucd94\uac00\n                throw new Exception($\"API \ud638\ucd9c \uc2e4\ud328: {response.StatusCode}\");\n\n            }\n        }\n    }\n}\n<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">CacheProvider<\/h3>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:c# decode:true \" title=\"CacheProvider\">using Microsoft.Extensions.Caching.Memory;\n\nnamespace InMemoryCacheCore.Infrastructure\n{\n    public interface ICacheProvider\n    {\n        T? GetFromCache&lt;T&gt;(string key) where T : class;\n        void SetCache&lt;T&gt;(string key, T value, MemoryCacheEntryOptions options) where T : class;\n        void ClearCache(string key);\n    }\n\n    public class CacheProvider : ICacheProvider\n    {\n        private readonly IMemoryCache _cache;\n\n        public CacheProvider(IMemoryCache cache)\n        {\n            _cache = cache;\n        }\n\n        public T? GetFromCache&lt;T&gt;(string key) where T : class\n        {\n            \/\/_cache.TryGetValue(key, out T cachedResponse);\n            \/\/return cachedResponse as T;\n            return _cache.Get&lt;T&gt;(key);\n        }\n\n        public void SetCache&lt;T&gt;(string key, T value, MemoryCacheEntryOptions options) where T : class\n        {\n            _cache.Set(key, value, options);\n        }\n\n        public void ClearCache(string key)\n        {\n            _cache.Remove(key);\n        }\n    }\n}\n\n<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Models-&gt;Airlines<\/h3>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:c# decode:true \" title=\"Model Airlines \">using System.Xml.Serialization;\n\nnamespace InMemoryCacheCore.Models\n{\n    [XmlRoot(ElementName = \"Root\")]\n    public class Root\n    {\n        [XmlElement(ElementName = \"Code\")]\n        public List&lt;Code&gt;? Code { get; set; }\n    }\n\n    [XmlRoot(ElementName = \"Code\")]\n    public class Code\n    {\n        [XmlElement(ElementName = \"Airlinecode\")]\n        public string Airlinecode { get; set; }\n\n        [XmlElement(ElementName = \"Airline3code\")]\n        public string? Airline3code { get; set; }\n\n        [XmlElement(ElementName = \"Airlinekor\")]\n        public string? Airlinekor { get; set; }\n\n        [XmlElement(ElementName = \"Airlineeng\")]\n        public string? Airlineeng { get; set; }\n    }\n}\n<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">CachedCodeService<\/h3>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:c# decode:true \" title=\"CachedCodeService\">using InMemoryCacheCore.Infrastructure;\nusing InMemoryCacheCore.Models;\nusing Microsoft.Extensions.Caching.Memory;\n\nnamespace InMemoryCacheCore.Services\n{\n    public class CachedCodeService : ICodeService\n    {\n        private readonly CodeService _codeService;\n        private readonly ICacheProvider _cacheProvider;\n        \n        private const int CacheTTLInSeconds = 100;\n        private readonly MemoryCacheEntryOptions cacheEntryOptions = new MemoryCacheEntryOptions()\n                    .SetSlidingExpiration(TimeSpan.FromSeconds(CacheTTLInSeconds));\n\n        private static readonly SemaphoreSlim GetUsersSemaphore = new(1, 1);\n\n        public CachedCodeService(CodeService codeService, ICacheProvider cacheProvider)\n        {\n            _codeService = codeService;\n            _cacheProvider = cacheProvider;\n        }\n\n        public async Task&lt;IEnumerable&lt;Code&gt;&gt; GetCodeAsync()\n        {\n            return await GetCachedResponse(\"_Codes\", GetUsersSemaphore, () =&gt; _codeService.GetCodeAsync());\n        }\n\n        private async Task&lt;IEnumerable&lt;Code&gt;&gt; GetCachedResponse(string cacheKey, SemaphoreSlim semaphore, Func&lt;Task&lt;IEnumerable&lt;Code&gt;&gt;&gt; func)\n        {\n            var users = _cacheProvider?.GetFromCache&lt;IEnumerable&lt;Code&gt;&gt;(cacheKey);\n            if (users != null) return users;\n\n            try\n            {\n                await semaphore.WaitAsync();\n\n                users = _cacheProvider?.GetFromCache&lt;IEnumerable&lt;Code&gt;&gt;(cacheKey); \/\/ Recheck to make sure it didn't populate before entering semaphore\n                if (users != null) return users;\n\n                users = await func();\n\n                _cacheProvider?.SetCache(cacheKey, users, cacheEntryOptions);\n            }\n            finally\n            {\n                semaphore.Release();\n            }\n\n            return users;\n        }\n\n        \n    }\n}\n<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">CacheService<\/h3>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:c# decode:true \" title=\"CacheService\">using InMemoryCacheCore.Infrastructure;\nusing InMemoryCacheCore.Models;\n\nnamespace InMemoryCacheCore.Services\n{\n    public interface ICacheService\n    {\n        IEnumerable&lt;Code&gt; GetCachedCode(string cacheKey);\n    }\n\n    public class CacheService : ICacheService\n    {\n        private readonly ICacheProvider _cacheProvider;\n\n        public CacheService(ICacheProvider cacheProvider) { \n            _cacheProvider = cacheProvider;\n        }\n        \n        public IEnumerable&lt;Code&gt; GetCachedCode(string cacheKey)\n        {\n            return _cacheProvider.GetFromCache&lt;IEnumerable&lt;Code&gt;&gt;(cacheKey);\n        }\n\n        public void ClearCache(string cachekey) {\n            _cacheProvider.ClearCache(cachekey);\n        }\n\n    }\n}\n<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">CodeService<\/h3>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:c# decode:true \" title=\"CodeService\">using InMemoryCacheCore.Infrastructure;\nusing InMemoryCacheCore.Models;\n\nnamespace InMemoryCacheCore.Services\n{\n    public interface ICodeService\n    {\n        Task&lt;IEnumerable&lt;Code&gt;&gt; GetCodeAsync();  \n    }\n\n    public class CodeService : ICodeService\n    {\n        private readonly IHttpClient _httpClient;   \n\n        public CodeService(IHttpClient httpClient)\n        {\n            _httpClient = httpClient;\n        }\n\n        public Task&lt;IEnumerable&lt;Code&gt;&gt; GetCodeAsync()\n        {\n            return _httpClient.Get();\n        }\n    }\n}\n<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Program.cs<\/h3>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:c decode:true \" title=\"Program.cs\">using InMemoryCacheCore.Infrastructure;\nusing InMemoryCacheCore.Services;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n\/\/ Add services to the container.\n\nbuilder.Services.AddControllers();\n\/\/ Learn more about configuring Swagger\/OpenAPI at https:\/\/aka.ms\/aspnetcore\/swashbuckle\nbuilder.Services.AddEndpointsApiExplorer();\nbuilder.Services.AddSwaggerGen();\n\n\/\/\nbuilder.Services.AddHttpClient();\n\nbuilder.Services.AddSingleton&lt;CodeService&gt;(); \/\/MainService\nbuilder.Services.AddSingleton&lt;ICodeService, CachedCodeService&gt;(); \/\/User \uc5f0\uacb0 \uc11c\ube44\uc2a4 \n\nbuilder.Services.AddSingleton&lt;ICacheService, CacheService&gt;();   \/\/\uce90\uc2f1 \uc11c\ube44\uc2a4  \nbuilder.Services.AddSingleton&lt;ICacheProvider, CacheProvider&gt;(); \/\/infrastructure\nbuilder.Services.AddSingleton&lt;IHttpClient, AirlineHttpClient&gt;();     \/\/infrastructure\nbuilder.Services.AddMemoryCache();\n\nvar app = builder.Build();\n\n\/\/ Configure the HTTP request pipeline.\nif (app.Environment.IsDevelopment())\n{\n    app.UseSwagger();\n    app.UseSwaggerUI();\n}\n\n\n app.UseHttpsRedirection();\n\n\napp.UseAuthorization();\n\napp.MapControllers();\n\napp.Run();\n<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Response body<\/h2>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:js decode:true \" title=\"200\">[\n  {\n    \"airlinecode\": \"0B\",\n    \"airline3code\": null,\n    \"airlinekor\": \"Blue Air\",\n    \"airlineeng\": null\n  },\n  {\n    \"airlinecode\": \"0J\",\n    \"airline3code\": null,\n    \"airlinekor\": \"Premium Jet AG\",\n    \"airlineeng\": null\n  },\n  {\n    \"airlinecode\": \"0Y\",\n    \"airline3code\": null,\n    \"airlinekor\": \"FlyYeti\",\n    \"airlineeng\": null\n  },\n  {\n    \"airlinecode\": \"1M\",\n    \"airline3code\": null,\n    \"airlinekor\": \"JSC Transport Auto Info Systems\",\n    \"airlineeng\": null\n  },\n  {\n    \"airlinecode\": \"1X\",\n    \"airline3code\": null,\n    \"airlinekor\": \"Branson Air Express\",\n    \"airlineeng\": null\n  },\n  {\n    \"airlinecode\": \"2A\",\n    \"airline3code\": null,\n    \"airlinekor\": \"Deutsche Bahn\",\n    \"airlineeng\": null\n  },\n  {\n    \"airlinecode\": \"2B\",\n    \"airline3code\": null,\n    \"airlinekor\": \"Albawings\",\n    \"airlineeng\": null\n  },\n  {\n    \"airlinecode\": \"2C\",\n    \"airline3code\": null,\n    \"airlinekor\": \"SNCF\",\n    \"airlineeng\": null\n  },\n  {\n    \"airlinecode\": \"2D\",\n    \"airline3code\": null,\n    \"airlinekor\": \"Dynamic Airways\",\n    \"airlineeng\": null\n  },\n  {\n    \"airlinecode\": \"2E\",\n    \"airline3code\": null,\n    \"airlinekor\": \"Smokey Bay Air\",\n    \"airlineeng\": null\n  },\n  {\n    \"airlinecode\": \"2G\",\n    \"airline3code\": null,\n    \"airlinekor\": \"DEBONAIR AIRWAYS\",\n    \"airlineeng\": null\n  },\n  {\n    \"airlinecode\": \"2I\",\n    \"airline3code\": null,\n    \"airlinekor\": \"Star Peru\",\n    \"airlineeng\": null\n  },\n  {\n    \"airlinecode\": \"2J\",\n    \"airline3code\": null,\n    \"airlinekor\": \"Air Burkina\",\n    \"airlineeng\": null\n  },\n  ............................\n]<\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><p>1. Memory Cache Simple sample 2. Memory Cache Interface sample (web XML Data) Web XML Data UML Program Files AirlineController AirlineHttpClient CacheProvider Models-&gt;Airlines CachedCodeService CacheService <a class=\"mh-excerpt-more\" href=\"https:\/\/www.auctionpro.co.kr\/?p=9019\" title=\"NetCore6.0  Memory Cache (Web XML Data)\">[&#8230;]<\/a><\/p>\n<\/div>","protected":false},"author":6,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[237],"tags":[],"class_list":["post-9019","post","type-post","status-publish","format-standard","hentry","category-memory-cache"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.auctionpro.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/9019","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.auctionpro.co.kr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.auctionpro.co.kr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.auctionpro.co.kr\/index.php?rest_route=\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/www.auctionpro.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=9019"}],"version-history":[{"count":0,"href":"https:\/\/www.auctionpro.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/9019\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.auctionpro.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=9019"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.auctionpro.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=9019"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.auctionpro.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=9019"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}