n-layered-architecture-with-azure-functions.-praktikada-n-layered-arxitektura

N-Layered Architecture with Azure functions. Praktikada N-Layered Arxitektura

Bu məqaləmizdə Remote developerin sərgüzəştlərini davam etdirərək işlədiyim layihələrdən birində köhnə (klassik ) WCF servisin Layered Azure proyektində handle olunmasını və Praktikada Layered arxitekturanı nəzərdən keçirəcəyik.

               Əgər .NET developer olaraq işə düzəlmisinizsə, çox gümankı işləyəcəyiniz şirkətdə çox az hallarda desktop application yazacaqsınız. (Təbii ki, bu işlədiyiniz şirkətin gördüyü işlərdən çox asılıdır) . Əksər hallarda .NET developerlər Asp.NET proyektlər və onun simasında Veb Servislər yazmaq ilə məşğul olurlar. İndiki dövrdə veb servis yazılması prosesi çox məşhurdur və görülən işlərin böyük bir qismi, köhnədən yazılmış servislərin yenisi ilə əvəzlənməsidir. Təbii ki, həmin servislər artıq işlək olduğuna görə, onları tamamilə 0-dan yazmaq lazım deyil.  Əksər hallarda sadəcə köhnə servisin üzərinə örtük yazaraq bu iş yerinə yetirilir. Yəni əlinizdə olan misalçün köhnə veb servisi ( asmx , WCF servis) siz Web API və ya Azure functionlarla əvəzləyirsiniz, onlar üzərinə wrapper yazırsınız. Hətta bir müddət əvvəl bəzi Azərbaycan bankları işə qəbul zamanı bu tipli tapşırıqlar verirdilər.(Yəqinki ənənə davam edir)

               Bu yazımızda, klassik WCF servisin Azure funksiyaya çevrilməsi prosesinə baxacağıq.

Bizim işlədiyimiz layihə 5 Layerdən ibarətdir. Burada Layerlərin sayı, arxutekturası təbii ki, Arxitektor tərəfindən verilir. Siz svc və ya ?wsdl linkinizi və credentialları aldıqdan sonra işə başlayırsınız.

İlk Layerimiz Proxy layerdir. Proxy layerin gördüyü əsas iş sadəcə Servisin generasiya olunub expose olunmasını təmin etməkdir.

Bu layerdə adəti üzrə əlavə kodlar yazmağa ehtiyac qalmır. Sadəcə Servisin istifadəsi üçün klasın fabrika mexanizmini düzəldirik (əgər buna həqiqətən ehtiyac varsa)

Bizim nümunədə obyektin yaradılması prosesini asanlaşdırmaq üçün statik fabrika məntiqi qurulub.

public class MortgageServiceFactory
    {
        public static ServiceOperationScope CreateService(string username, string password, string endpointAddress)
        {
            var application = HttpSoapClientFactory.CreateSecureClient(endpointAddress);

            var operationScope = new OperationContextScope(application.InnerChannel);

            OperationContext.Current.OutgoingMessageHeaders.AddWssSecurityHeader(username, password);

            ServiceOperationScope _scope = new ServiceOperationScope
            {
                Application = application,
                OperationContextScope = operationScope
            };
            
            return _scope;
        }
    }

Web servisin verdiyi modellərdən asılılığı aradan qaldırmaq üçün öz modellərimizi yaradır və Client layerin servis layerlə kommunikasiyasi üçün bu modelləri istifadə edirik. Həmçinin Client Layer servis layerdən minimal asılı olsun deyə xüsusi Client Layer interfeysi ayrılır.

	 public interface IApplicationClient
    {
        GMApplicationAckDef UpdateApplication(GMApplicationRequest GnwApplicationRequest);
        GMApplicationAckDef CancelApplication(GMApplicationRequest GnwApplicationRequest);
        GMApplicationAckDef AddApplication(GMApplicationRequest GnwApplicationRequest);
        GMApplicationResponse InquireApplicationStatus(GMStatusRequestDef ApplicationStatusRequest);
    }

public class GenworthMortgageApplicationClient : IApplicationClient
    {
        #region injecting dependencies
        private readonly MortgageAppConfiguration _mortgageConfiguration;
        private readonly ILogger _logger;
        private readonly IMapper _mapper;
        public GenworthMortgageApplicationClient(MortgageAppConfiguration mortgageConfiguration
                                       , ILogger logger
                                       ,IMapper mapper)
        {
            _mortgageConfiguration = mortgageConfiguration;
            _logger = logger;
            _mapper = mapper;
        }
        #endregion

 
   public GMApplicationAckDef CancelApplication(GMApplicationRequest GnwApplicationRequest)
        {
            ServiceOperationScope applicationClient = null;
            try
            {
                _logger.LogInformation("CancelApplication started..");

                applicationClient = MortgageServiceFactory.CreateService(_mortgageConfiguration.Username, _mortgageConfiguration.Password, _mortgageConfiguration.EndPointAddress);

                var applicationRequest = _mapper.Map(GnwApplicationRequest);

                string requestAsXml = new ObjectXmlDecorator(applicationRequest).AsXml();

                _logger.LogInformation($"CancelApplication Request params are : {requestAsXml}");

                var response = applicationClient.Application.CancelApplication(applicationRequest);

                _logger.LogInformation($"CancelApplication Response params are : {response}");

                var responseModel = _mapper.Map(response);

                _logger.LogInformation("CancelApplication ended..");

                applicationClient.Dispose();

                return responseModel;
            }
            catch (System.Exception ex)
            {
                _logger.LogError(ex.Message);
                throw;
            }
            finally
            {
                applicationClient?.Dispose();
            }
        }
..............
}

Servis layer isə əsasən nəzərdə tutulduğu kimi, gələn modellərin validasiyası, məlumatların düzgün daxil edilməsi kimi məsələlərə nəzarət edir və hər şey qaydasındadırsa Client layer funksionallığını işə salır.

	 public interface IApplicationClientProvider
    {
        GMApplicationAckDef UpdateApplication(GMApplicationRequest GnwApplicationRequest);
        GMApplicationAckDef CancelApplication(GMApplicationRequest GnwApplicationRequest);
        GMApplicationAckDef AddApplication(GMApplicationRequest GnwApplicationRequest);
        GMApplicationResponse InquireApplicationStatus(GMStatusRequestDef ApplicationStatusRequest);
        Task PushInsuranceAppStatusAsync(string request);
    }

public class ApplicationClientProvider : IApplicationClientProvider
    {
        private readonly IApplicationClient _applicationClient;
        private readonly GenworthServiceBusConfiguration _serviceBusConfiguration;
        private CloudQueueClient _cloudQueueClient;

        public ApplicationClientProvider(IApplicationClient applicationClient
            , GenworthServiceBusConfiguration serviceBusConfiguration)
        {
            _applicationClient = applicationClient;
            _serviceBusConfiguration = serviceBusConfiguration;
        }

        public GMApplicationAckDef CancelApplication(GMApplicationRequest GnwApplicationRequest)
        {
            try
            {
                var validator = new GMCancelApplicationRequestValidator();
                var result = validator.Validate(GnwApplicationRequest);

                if (!result.IsValid)
                {
                    var exceptionMessage = result.GetServiceExceptionErrors();

                    throw new ServiceException(exceptionMessage);
                }
                return _applicationClient.CancelApplication(GnwApplicationRequest);
            }
            catch (ServiceException)
            {
                throw;
            }
            catch (Exception exp)
            {
                throw new ServiceException(exp.Message);
            }
        }
.........
}

Və təbii ki, bugünki mövzumuzun əsas qəhrəmanı olan Azure functions layer. Burada istifadəçidən məlumatın daxil edilməsi və müvafiq olaraq servis layerə göndərilməsi prosesi yerinə yetirilir.

 public class GnwMortgageFunctions
    {
        private readonly ILogger _logger;
        private readonly IApplicationClientProvider _applicationClientProvider;

        public GnwMortgageFunctions(ILogger logger,
            IApplicationClientProvider applicationClientProvider)
        {
            _logger = logger;
            _applicationClientProvider = applicationClientProvider;
        }


        [FunctionName("CancelApplication")]
        public async Task CancelApplication([HttpTrigger(AuthorizationLevel.Function, "post", Route = "gnw/cancel")] HttpRequest req)
        {
            try
            {
                _logger.LogInformation("CancelApplication started..");

                var requestBody = await new StreamReader(req.Body).ReadToEndAsync();

                JObject obj = JObject.Parse(requestBody);

                var request = obj.ToObject();

                var response = _applicationClientProvider.CancelApplication(request);
                
                _logger.LogInformation("CancelApplication finished..");

                return new OkObjectResult(response);
            }
            catch (ServiceException ex)
            {
                _logger.LogError(ex, "CancelApplication Failed");
                return new BadResponseErrorResult(ex);
            }
            catch(Exception exp)
            {
                _logger.LogError(exp, "CancelApplication Failed");
                var _exp = new ServiceException(exp.Message);
                return new BadResponseErrorResult(_exp);
            }
        }
    }

Servislerin registrasiyası vahid mərkəzdən idarə olunsun deyə asılılıqların hamısı Startup faylında yerləşdirilir. ( Bu bizim razılaşma qaydamızdır, sizdə fərqli ola bilər )

 public class Startup : FunctionsStartup
    {
        public IConfiguration Configuration { get; }

        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddLogging(logging =>
            {
                logging.AddNLog();
            });

            var config = new ConfigurationBuilder()
                 .AddEnvironmentVariables()
                 .Build();

            builder.Services.AddAutoMapper(Assembly.GetAssembly(typeof(CertifaxApplicationProfile)),
                                           Assembly.GetAssembly(typeof(DocumentCreationProfile)));

            builder.Services
                     .AddCGuarantyService(config, bindKey: "CGuaranty");

            builder.Services
                       .AddGenworthService(config, bindKey: "GnwMortgage");

            builder.Services
                      .AddManulifeService(config, bindKey: "Manulife");
            
            builder.Services
                      .AddHomeVaultService(config, bindKey: "HomeVault");

            builder.Services
                     .AddGenWorthServiceBusConfiguration(config, bindKey: "Genworth:ServiceBus");
            //setting current directory for nlog , for saving logs, can be change if needed
            var startupDirectory = System.IO.Directory.GetCurrentDirectory();
            NLog.LayoutRenderers.LayoutRenderer.Register("startupdir", (logEvent) => startupDirectory);
        }
    }

 

Tural

Tural Süleymani

Süleymani Tural Microsoft-un MCSD statuslu mütəxəssisidir, 2008-ci ildən bu yana proqramlaşdırma üzrə tədris aparır

Müəllifin bu dildə ən son postları

Bu yazıları da bəyənə bilərsiniz