最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

通過(guò)lms.samples熟悉lms微服務(wù)框架的使用詳解

 更新時(shí)間:2021年04月08日 15:15:48   作者:懶小蟲(chóng)  
這篇文章主要介紹了通過(guò)lms.samples熟悉lms微服務(wù)框架的使用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

經(jīng)過(guò)一段時(shí)間的開(kāi)發(fā)與測(cè)試,終于發(fā)布了Lms框架的第一個(gè)正式版本(1.0.0版本),并給出了lms框架的樣例項(xiàng)目lms.samples。本文通過(guò)對(duì)lms.samples的介紹,簡(jiǎn)述如何通過(guò)lms框架快速的構(gòu)建一個(gè)微服務(wù)的業(yè)務(wù)框架,并進(jìn)行應(yīng)用開(kāi)發(fā)。

lms.samples項(xiàng)目基本介紹

lms.sample項(xiàng)目由三個(gè)獨(dú)立的微服務(wù)應(yīng)用模塊組成:account、stock、order和一個(gè)網(wǎng)關(guān)項(xiàng)目gateway構(gòu)成。

業(yè)務(wù)應(yīng)用模塊

每個(gè)獨(dú)立的微服務(wù)應(yīng)用采用模塊化設(shè)計(jì),主要由如下幾部分組成:

  1. 主機(jī)(Host): 主要用于托管微服務(wù)應(yīng)用本身,主機(jī)通過(guò)引用應(yīng)用服務(wù)項(xiàng)目(應(yīng)用接口的實(shí)現(xiàn)),托管微服務(wù)應(yīng)用,通過(guò)托管應(yīng)用服務(wù),在主機(jī)啟動(dòng)的過(guò)程中,向服務(wù)注冊(cè)中心注冊(cè)服務(wù)路由。
  2. 應(yīng)用接口層(Application.Contracts): 用于定義應(yīng)用服務(wù)接口,通過(guò)應(yīng)用接口,該微服務(wù)模塊與其他微服務(wù)模塊或是網(wǎng)關(guān)進(jìn)行rpc通信的能力。在該項(xiàng)目中,除了定義應(yīng)用服務(wù)接口之前,一般還定義與該應(yīng)用接口相關(guān)的DTO對(duì)象。應(yīng)用接口除了被該微服務(wù)應(yīng)用項(xiàng)目引用,并實(shí)現(xiàn)應(yīng)用服務(wù)之前,還可以被網(wǎng)關(guān)或是其他微服務(wù)模塊引用。網(wǎng)關(guān)或是其他微服務(wù)項(xiàng)目通過(guò)應(yīng)用接口生成的代理與該微服務(wù)模塊通過(guò)rpc進(jìn)行通信。
  3. 應(yīng)用服務(wù)層(Application): 應(yīng)用服務(wù)是該微服務(wù)定義的應(yīng)用接口的實(shí)現(xiàn)。應(yīng)用服務(wù)與DDD傳統(tǒng)分層架構(gòu)的應(yīng)用層的概念一致。主要負(fù)責(zé)外部通信與領(lǐng)域?qū)又g的協(xié)調(diào)。一般地,應(yīng)用服務(wù)進(jìn)行業(yè)務(wù)流程控制,但是不包含業(yè)務(wù)邏輯的實(shí)現(xiàn)。
  4. 領(lǐng)域?qū)?Domain): 負(fù)責(zé)表達(dá)業(yè)務(wù)概念,業(yè)務(wù)狀態(tài)信息以及業(yè)務(wù)規(guī)則,是該微服務(wù)模塊的業(yè)務(wù)核心。一般地,在該層可以定義聚合根、實(shí)體、領(lǐng)域服務(wù)等對(duì)象。
  5. 領(lǐng)域共享層(Domain.Shared): 該層用于定義與領(lǐng)域?qū)ο笙嚓P(guān)的模型、實(shí)體等相關(guān)類(lèi)型。不包含任何業(yè)務(wù)實(shí)現(xiàn),可以被其他微服務(wù)引用。
  6. 數(shù)據(jù)訪問(wèn)(DataAccess)層: 該層一般用于封裝數(shù)據(jù)訪問(wèn)相關(guān)的對(duì)象。例如:倉(cāng)庫(kù)對(duì)象、 SqlHelper、或是ORM相關(guān)的類(lèi)型等。在lms.samples中,通過(guò)efcore實(shí)現(xiàn)數(shù)據(jù)的讀寫(xiě)操作。

服務(wù)聚合與網(wǎng)關(guān)

lms框架不允許服務(wù)外部與微服務(wù)主機(jī)直接通信,應(yīng)用請(qǐng)求必須通過(guò)http請(qǐng)求到達(dá)網(wǎng)關(guān),網(wǎng)關(guān)通過(guò)lms提供的中間件解析到服務(wù)條目,并通過(guò)rpc與集群內(nèi)部的微服務(wù)進(jìn)行通信。所以,如果服務(wù)需要與集群外部進(jìn)行通信,那么,開(kāi)發(fā)者定義的網(wǎng)關(guān)必須要引用各個(gè)微服務(wù)模塊的應(yīng)用接口層;以及必須要使用lms相關(guān)的中間件。

開(kāi)發(fā)環(huán)境

  1. .net版本: 5.0.101
  2. lms版本: 1.0.0
  3. IDE: (1) visual studio 最新版 (2) Rider(推薦)

主機(jī)與應(yīng)用托管

主機(jī)的創(chuàng)建步驟

通過(guò)lms框架創(chuàng)建一個(gè)業(yè)務(wù)模塊非常方便,只需要通過(guò)如下4個(gè)步驟,就可以輕松的創(chuàng)建一個(gè)lms應(yīng)用業(yè)務(wù)模塊。

1.創(chuàng)建項(xiàng)目

創(chuàng)建控制臺(tái)應(yīng)用(Console Application)項(xiàng)目,并且引用Silky.Lms.NormHost包。

dotnet add package Silky.Lms.NormHost --version 1.0.0

2.應(yīng)用程序入口與主機(jī)構(gòu)建

main方法中,通用.net的主機(jī)Host構(gòu)建并注冊(cè)lms微服務(wù)。在注冊(cè)lms微服務(wù)時(shí),需要指定lms啟動(dòng)的依賴(lài)模塊。

一般地,如果開(kāi)發(fā)者不需要額外依賴(lài)其他模塊,也無(wú)需在應(yīng)用啟動(dòng)或停止時(shí)執(zhí)行方法,那么您可以直接指定NormHostModule模塊。

 public class Program
    {
        public static async Task Main(string[] args)
        {
            await CreateHostBuilder(args).Build().RunAsync();
        }

        private static IHostBuilder CreateHostBuilder(string[] args)
        {
            return Host.CreateDefaultBuilder(args)
                    .RegisterLmsServices<NormHostModule>()
                ;
        }
    }

3.配置文件

lms框架支持yml或是json格式作為配置文件。通過(guò)appsettings.yml對(duì)lms框架進(jìn)行統(tǒng)一配置,通過(guò)appsettings.${Environment}.yml對(duì)不同環(huán)境變量下的配置項(xiàng)進(jìn)行設(shè)置。

開(kāi)發(fā)者如果直接通過(guò)項(xiàng)目的方式啟動(dòng)應(yīng)用,那么可以通過(guò)Properties/launchSettings.jsonenvironmentVariables.DOTNET_ENVIRONMENT環(huán)境變量。如果通過(guò)docker-compose的方式啟動(dòng)應(yīng)用,那么可以通過(guò).env設(shè)置DOTNET_ENVIRONMENT環(huán)境變量。

為保證配置文件有效,開(kāi)發(fā)者需要顯式的將配置文件拷貝到項(xiàng)目生成目錄下。

4.引用應(yīng)用服務(wù)層和數(shù)據(jù)訪問(wèn)層

一般地,主機(jī)項(xiàng)目需要引用該微服務(wù)模塊的應(yīng)用服務(wù)層和數(shù)據(jù)訪問(wèn)層。只有主機(jī)引用應(yīng)用服務(wù)層,主機(jī)在啟動(dòng)時(shí),才會(huì)生成服務(wù)條目的路由,并且將服務(wù)路由注冊(cè)到服務(wù)注冊(cè)中心。

一個(gè)典型的主機(jī)項(xiàng)目文件如下所示:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net5.0</TargetFramework>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="Silky.Lms.NormHost" Version="$(LmsVersion)" />
    </ItemGroup>

    <ItemGroup>
      <None Update="appsettings.yml">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      </None>
      <None Update="appsettings.Production.yml">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      </None>
      <None Update="appsettings.Development.yml">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      </None>
    </ItemGroup>

    <ItemGroup>
      <ProjectReference Include="..\Lms.Account.Application\Lms.Account.Application.csproj" />
      <ProjectReference Include="..\Lms.Account.EntityFrameworkCore\Lms.Account.EntityFrameworkCore.csproj" />
    </ItemGroup>
</Project>

配置

一般地,一個(gè)微服務(wù)模塊的主機(jī)必須要配置:服務(wù)注冊(cè)中心、分布式鎖鏈接、分布式緩存地址、集群rpc通信token、數(shù)據(jù)庫(kù)鏈接地址等。

如果使用docker-compose來(lái)啟動(dòng)和調(diào)試應(yīng)用的話,那么,rpc配置節(jié)點(diǎn)下的的host和port可以缺省,因?yàn)樯傻拿總€(gè)容器的都有自己的地址和端口號(hào)。

如果直接通過(guò)項(xiàng)目的方式啟動(dòng)和調(diào)試應(yīng)用的話,那么,必須要配置rpc節(jié)點(diǎn)下的port,每個(gè)微服務(wù)模塊的主機(jī)應(yīng)用有自己的端口號(hào)。

lms框架的必要配置如下所示:

rpc:
  host: 0.0.0.0
  rpcPort: 2201
  token: ypjdYOzNd4FwENJiEARMLWwK0v7QUHPW
registrycenter:
  connectionStrings: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183;127.0.0.1:2184,127.0.0.1:2185,127.0.0.1:2186 # 使用分號(hào);來(lái)區(qū)分不同的服務(wù)注冊(cè)中心
  registryCenterType: Zookeeper
distributedCache:
  redis:
    isEnabled: true 
    configuration: 127.0.0.1:6379,defaultDatabase=0
lock:
  lockRedisConnection: 127.0.0.1:6379,defaultDatabase=1
connectionStrings:
    default: server=127.0.0.1;port=3306;database=account;uid=root;pwd=qwe!P4ss;

應(yīng)用接口

應(yīng)用接口定義

一般地,在應(yīng)用接口層開(kāi)發(fā)者需要安裝Silky.Lms.Rpc包。如果該微服務(wù)模塊還涉及到分布式事務(wù),那么還需要安裝Silky.Lms.Transaction.Tcc,當(dāng)然,您也可以選擇在應(yīng)用接口層安裝Silky.Lms.Transaction包,在應(yīng)用服務(wù)層安裝Silky.Lms.Transaction.Tcc包。

  1. 開(kāi)發(fā)者只需要在應(yīng)用接口通過(guò)ServiceRouteAttribute特性對(duì)應(yīng)用接口進(jìn)行直接即可。
  2. Lms約定應(yīng)用接口應(yīng)當(dāng)以IXxxAppService命名,這樣,服務(wù)條目生成的路由則會(huì)以api/xxx形式生成。當(dāng)然這并不是強(qiáng)制的。
  3. 每個(gè)應(yīng)用接口的方法都對(duì)應(yīng)著一個(gè)服務(wù)條目,服務(wù)條目的Id為: 方法的完全限定名 + 參數(shù)名
  4. 您可以在應(yīng)用接口層對(duì)方法的緩存、路由、服務(wù)治理、分布式事務(wù)進(jìn)行相關(guān)配置。該部分內(nèi)容請(qǐng)參考官方文檔
  5. 網(wǎng)關(guān)或是其他模塊的微服務(wù)項(xiàng)目需要引用服務(wù)應(yīng)用接口項(xiàng)目或是通過(guò)nuget的方式安裝服務(wù)應(yīng)用接口生成的包。
  6. [Governance(ProhibitExtranet = true)]可以標(biāo)識(shí)一個(gè)方法禁止與集群外部進(jìn)行通信,通過(guò)網(wǎng)關(guān)也不會(huì)生成swagger文檔。
  7. 應(yīng)用接口方法生成的WebApi支持restful API風(fēng)格。Lms支持通過(guò)方法的約定命名生成對(duì)應(yīng)http方法請(qǐng)求的WebApi。您當(dāng)然開(kāi)發(fā)者也可以通過(guò)HttpMethodAttribute特性對(duì)某個(gè)方法進(jìn)行注解。

一個(gè)典型的應(yīng)用接口的定義

/// <summary>
    /// 賬號(hào)服務(wù)
    /// </summary>
    [ServiceRoute]
    public interface IAccountAppService
    {
        /// <summary>
        /// 新增賬號(hào)
        /// </summary>
        /// <param name="input">賬號(hào)信息</param>
        /// <returns></returns>
        Task<GetAccountOutput> Create(CreateAccountInput input);

        /// <summary>
        /// 通過(guò)賬號(hào)名稱(chēng)獲取賬號(hào)
        /// </summary>
        /// <param name="name">賬號(hào)名稱(chēng)</param>
        /// <returns></returns>
        [GetCachingIntercept("Account:Name:{0}")]
        [HttpGet("{name:string}")]
        Task<GetAccountOutput> GetAccountByName([CacheKey(0)] string name);

        /// <summary>
        /// 通過(guò)Id獲取賬號(hào)信息
        /// </summary>
        /// <param name="id">賬號(hào)Id</param>
        /// <returns></returns>
        [GetCachingIntercept("Account:Id:{0}")]
        [HttpGet("{id:long}")]
        Task<GetAccountOutput> GetAccountById([CacheKey(0)] long id);

        /// <summary>
        /// 更新賬號(hào)信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [UpdateCachingIntercept( "Account:Id:{0}")]
        Task<GetAccountOutput> Update(UpdateAccountInput input);

        /// <summary>
        /// 刪除賬號(hào)信息
        /// </summary>
        /// <param name="id">賬號(hào)Id</param>
        /// <returns></returns>
        [RemoveCachingIntercept("GetAccountOutput","Account:Id:{0}")]
        [HttpDelete("{id:long}")]
        Task Delete([CacheKey(0)]long id);

        /// <summary>
        /// 訂單扣款
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [Governance(ProhibitExtranet = true)]
        [RemoveCachingIntercept("GetAccountOutput","Account:Id:{0}")]
        [Transaction]
        Task<long?> DeductBalance(DeductBalanceInput input);
    }

應(yīng)用服務(wù)--應(yīng)用接口的實(shí)現(xiàn)

  1. 應(yīng)用服務(wù)層只需要引用應(yīng)用服務(wù)接口層以及領(lǐng)域服務(wù)層,并實(shí)現(xiàn)應(yīng)用接口相關(guān)的方法。
  2. 確保該微服務(wù)模塊的主機(jī)引用了該模塊的應(yīng)用服務(wù)層,這樣主機(jī)才能夠托管該應(yīng)用本身。
  3. 應(yīng)用服務(wù)層可以通過(guò)引用其他微服務(wù)模塊的應(yīng)用接口層項(xiàng)目(或是安裝nuget包,取決于開(kāi)發(fā)團(tuán)隊(duì)的項(xiàng)目管理方法),與其他微服務(wù)模塊進(jìn)行rpc通信。
  4. 應(yīng)用服務(wù)層需要依賴(lài)領(lǐng)域服務(wù),通過(guò)調(diào)用領(lǐng)域服務(wù)的相關(guān)接口,實(shí)現(xiàn)該模塊的核心業(yè)務(wù)邏輯。
  5. DTO到實(shí)體對(duì)象或是實(shí)體對(duì)DTO對(duì)象的映射關(guān)系可以在該層指定映射關(guān)系。

一個(gè)典型的應(yīng)用服務(wù)的實(shí)現(xiàn)如下所示:

public class AccountAppService : IAccountAppService
    {
        private readonly IAccountDomainService _accountDomainService;

        public AccountAppService(IAccountDomainService accountDomainService)
        {
            _accountDomainService = accountDomainService;
        }

        public async Task<GetAccountOutput> Create(CreateAccountInput input)
        {
            var account = input.MapTo<Domain.Accounts.Account>();
            account = await _accountDomainService.Create(account);
            return account.MapTo<GetAccountOutput>();
        }

        public async Task<GetAccountOutput> GetAccountByName(string name)
        {
            var account = await _accountDomainService.GetAccountByName(name);
            return account.MapTo<GetAccountOutput>();
        }

        public async Task<GetAccountOutput> GetAccountById(long id)
        {
            var account = await _accountDomainService.GetAccountById(id);
            return account.MapTo<GetAccountOutput>();
        }

        public async Task<GetAccountOutput> Update(UpdateAccountInput input)
        {
            var account = await _accountDomainService.Update(input);
            return account.MapTo<GetAccountOutput>();
        }

        public Task Delete(long id)
        {
            return _accountDomainService.Delete(id);
        }

        [TccTransaction(ConfirmMethod = "DeductBalanceConfirm", CancelMethod = "DeductBalanceCancel")]
        public async Task<long?> DeductBalance(DeductBalanceInput input)
        {
            var account = await _accountDomainService.GetAccountById(input.AccountId);
            if (input.OrderBalance > account.Balance)
            {
                throw new BusinessException("賬號(hào)余額不足");
            }
            return await _accountDomainService.DeductBalance(input, TccMethodType.Try);
        }

        public Task DeductBalanceConfirm(DeductBalanceInput input)
        {
            return _accountDomainService.DeductBalance(input, TccMethodType.Confirm);
        }

        public Task DeductBalanceCancel(DeductBalanceInput input)
        {
            return _accountDomainService.DeductBalance(input, TccMethodType.Cancel);
        }
    }

領(lǐng)域?qū)?-微服務(wù)的核心業(yè)務(wù)實(shí)現(xiàn)

  1. 領(lǐng)域?qū)邮窃撐⒎?wù)模塊核心業(yè)務(wù)處理的模塊,一般用于定于聚合根、實(shí)體、領(lǐng)域服務(wù)、倉(cāng)儲(chǔ)等業(yè)務(wù)對(duì)象。
  2. 領(lǐng)域?qū)右迷撐⒎?wù)模塊的應(yīng)用接口層,方便使用dto對(duì)象。
  3. 領(lǐng)域?qū)涌梢酝ㄟ^(guò)引用其他微服務(wù)模塊的應(yīng)用接口層項(xiàng)目(或是安裝nuget包,取決于開(kāi)發(fā)團(tuán)隊(duì)的項(xiàng)目管理方法),與其他微服務(wù)模塊進(jìn)行rpc通信。
  4. 領(lǐng)域服務(wù)必須要直接或間接繼承ITransientDependency接口,這樣,該領(lǐng)域服務(wù)才會(huì)被注入到ioc容器。
  5. lms.samples 項(xiàng)目使用TanvirArjel.EFCore.GenericRepository包實(shí)現(xiàn)數(shù)據(jù)的讀寫(xiě)操作。

一個(gè)典型的領(lǐng)域服務(wù)的實(shí)現(xiàn)如下所示:

public class AccountDomainService : IAccountDomainService
    {
        private readonly IRepository _repository;
        private readonly IDistributedCache<GetAccountOutput, string> _accountCache;

        public AccountDomainService(IRepository repository,
            IDistributedCache<GetAccountOutput, string> accountCache)
        {
            _repository = repository;
            _accountCache = accountCache;
        }

        public async Task<Account> Create(Account account)
        {
            var exsitAccountCount = await _repository.GetCountAsync<Account>(p => p.Name == account.Name);
            if (exsitAccountCount > 0)
            {
                throw new BusinessException($"已經(jīng)存在{account.Name}名稱(chēng)的賬號(hào)");
            }

            exsitAccountCount = await _repository.GetCountAsync<Account>(p => p.Email == account.Email);
            if (exsitAccountCount > 0)
            {
                throw new BusinessException($"已經(jīng)存在{account.Email}Email的賬號(hào)");
            }

            await _repository.InsertAsync<Account>(account);
            return account;
        }

        public async Task<Account> GetAccountByName(string name)
        {
            var accountEntry = _repository.GetQueryable<Account>().FirstOrDefault(p => p.Name == name);
            if (accountEntry == null)
            {
                throw new BusinessException($"不存在名稱(chēng)為{name}的賬號(hào)");
            }

            return accountEntry;
        }

        public async Task<Account> GetAccountById(long id)
        {
            var accountEntry = _repository.GetQueryable<Account>().FirstOrDefault(p => p.Id == id);
            if (accountEntry == null)
            {
                throw new BusinessException($"不存在Id為{id}的賬號(hào)");
            }

            return accountEntry;
        }

        public async Task<Account> Update(UpdateAccountInput input)
        {
            var account = await GetAccountById(input.Id);
            if (!account.Email.Equals(input.Email))
            {
                var exsitAccountCount = await _repository.GetCountAsync<Account>(p => p.Email == input.Email);
                if (exsitAccountCount > 0)
                {
                    throw new BusinessException($"系統(tǒng)中已經(jīng)存在Email為{input.Email}的賬號(hào)");
                }
            }

            if (!account.Name.Equals(input.Name))
            {
                var exsitAccountCount = await _repository.GetCountAsync<Account>(p => p.Name == input.Name);
                if (exsitAccountCount > 0)
                {
                    throw new BusinessException($"系統(tǒng)中已經(jīng)存在Name為{input.Name}的賬號(hào)");
                }
            }

            await _accountCache.RemoveAsync($"Account:Name:{account.Name}");
            account = input.MapTo(account);
            await _repository.UpdateAsync(account);
            return account;
        }

        public async Task Delete(long id)
        {
            var account = await GetAccountById(id);
            await _accountCache.RemoveAsync($"Account:Name:{account.Name}");
            await _repository.DeleteAsync(account);
        }

        public async Task<long?> DeductBalance(DeductBalanceInput input, TccMethodType tccMethodType)
        {
            var account = await GetAccountById(input.AccountId);
            var trans = await _repository.BeginTransactionAsync();
            BalanceRecord balanceRecord = null;
            switch (tccMethodType)
            {
                case TccMethodType.Try:
                    account.Balance -= input.OrderBalance;
                    account.LockBalance += input.OrderBalance;
                    balanceRecord = new BalanceRecord()
                    {
                        OrderBalance = input.OrderBalance,
                        OrderId = input.OrderId,
                        PayStatus = PayStatus.NoPay
                    };
                    await _repository.InsertAsync(balanceRecord);
                    RpcContext.GetContext().SetAttachment("balanceRecordId",balanceRecord.Id);
                    break;
                case TccMethodType.Confirm:
                    account.LockBalance -= input.OrderBalance;
                    var balanceRecordId1 = RpcContext.GetContext().GetAttachment("orderBalanceId")?.To<long>();
                    if (balanceRecordId1.HasValue)
                    {
                        balanceRecord = await _repository.GetByIdAsync<BalanceRecord>(balanceRecordId1.Value);
                        balanceRecord.PayStatus = PayStatus.Payed;
                        await _repository.UpdateAsync(balanceRecord);
                    }
                    break;
                case TccMethodType.Cancel:
                    account.Balance += input.OrderBalance;
                    account.LockBalance -= input.OrderBalance;
                    var balanceRecordId2 = RpcContext.GetContext().GetAttachment("orderBalanceId")?.To<long>();
                    if (balanceRecordId2.HasValue)
                    {
                        balanceRecord = await _repository.GetByIdAsync<BalanceRecord>(balanceRecordId2.Value);
                        balanceRecord.PayStatus = PayStatus.Cancel;
                        await _repository.UpdateAsync(balanceRecord);
                    }
                    break;
            }

           
            await _repository.UpdateAsync(account);
            await trans.CommitAsync();
            await _accountCache.RemoveAsync($"Account:Name:{account.Name}");
            return balanceRecord?.Id;
        }
    }

數(shù)據(jù)訪問(wèn)(EntityFrameworkCore)--通過(guò)efcore實(shí)現(xiàn)數(shù)據(jù)讀寫(xiě)

  • lms.samples項(xiàng)目使用orm框架efcore進(jìn)行數(shù)據(jù)讀寫(xiě)。
  • lms提供了IConfigureService,通過(guò)繼承該接口即可使用IServiceCollection的實(shí)例指定數(shù)據(jù)上下文對(duì)象和注冊(cè)倉(cāng)庫(kù)服務(wù)。
public class EfCoreConfigureService : IConfigureService
    {
        public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
        {
            services.AddDbContext<OrderDbContext>(opt =>
                    opt.UseMySql(configuration.GetConnectionString("Default"),
                        ServerVersion.AutoDetect(configuration.GetConnectionString("Default"))))
                .AddGenericRepository<OrderDbContext>(ServiceLifetime.Transient)
                ;
        }

        public int Order { get; } = 1;
    }

3.主機(jī)項(xiàng)目需要顯式的引用該項(xiàng)目,只有這樣,該項(xiàng)目的ConfigureServices才會(huì)被調(diào)用。

4.數(shù)據(jù)遷移,請(qǐng)參考

應(yīng)用啟動(dòng)與調(diào)試

獲取源碼

1.使用git 克隆lms項(xiàng)目源代碼,lms.samples存放在samples目錄下

# github
git clone https://github.com/liuhll/lms.git

# gitee
git clone https://gitee.com/liuhll2/lms.git

必要的前提

  1. 服務(wù)注冊(cè)中心zookeeper
  2. 緩存服務(wù)redis
  3. mysql數(shù)據(jù)庫(kù)

如果您電腦已經(jīng)安裝了docker以及docker-compose命令,那么您只需要進(jìn)入samples\docker-compose\infrastr目錄下,打開(kāi)命令行工作,執(zhí)行如下命令就可以自動(dòng)安裝zookeeper、redismysql等服務(wù):

docker-compose -f .\docker-compose.mysql.yml -f .\docker-compose.redis.yml -f .\docker-compose.zookeeper.yml up -d

數(shù)據(jù)庫(kù)遷移

需要分別進(jìn)入到各個(gè)微服務(wù)模塊下的EntityFrameworkCore項(xiàng)目(例如:),執(zhí)行如下命令:

dotnet ef database update

例如: 需要遷移account模塊的數(shù)據(jù)庫(kù)如下所示:

order模塊和stock模塊與account模塊一致,在服務(wù)運(yùn)行前都需要通過(guò)數(shù)據(jù)庫(kù)遷移命令生成相關(guān)數(shù)據(jù)庫(kù)。

  1. 數(shù)據(jù)庫(kù)遷移指定數(shù)據(jù)庫(kù)連接地址默認(rèn)指定的是appsettings.Development.yml中配置的,您可以通過(guò)修改該配置文件中的connectionStrings.default配置項(xiàng)來(lái)指定自己的數(shù)據(jù)庫(kù)服務(wù)地址。
  2. 如果沒(méi)有dotnet ef命令,則需要通過(guò)dotnet tool install --global dotnet-ef安裝ef工具,請(qǐng)[參考] (https://docs.microsoft.com/zh-cn/ef/core/get-started/overview/install)

以項(xiàng)目的方式啟動(dòng)和調(diào)試

使用visual studio作為開(kāi)發(fā)工具

進(jìn)入到samples目錄下,使用visual studio打開(kāi)lms.samples.sln解決方案,將項(xiàng)目設(shè)置為多啟動(dòng)項(xiàng)目,并將網(wǎng)關(guān)和各個(gè)模塊的微服務(wù)主機(jī)設(shè)置為啟動(dòng)項(xiàng)目,如下圖:

設(shè)置完成后直接啟動(dòng)即可。

使用rider作為開(kāi)發(fā)工具進(jìn)入到samples目錄下,使用rider打開(kāi)lms.samples.sln解決方案,打開(kāi)各個(gè)微服務(wù)模塊下的Properties/launchSettings.json,點(diǎn)擊圖中綠色的箭頭即可啟動(dòng)項(xiàng)目。

啟動(dòng)網(wǎng)關(guān)項(xiàng)目后,可以看到應(yīng)用接口的服務(wù)條目生成的swagger api文檔 http://localhost:5000/swagger。

默認(rèn)的環(huán)境變量為: Development,如果需要修改環(huán)境變量的話,可以通過(guò)Properties/launchSettings.json下的environmentVariables節(jié)點(diǎn)修改相關(guān)環(huán)境變量,請(qǐng)參考在 ASP.NET Core 中使用多個(gè)環(huán)境

數(shù)據(jù)庫(kù)連接、服務(wù)注冊(cè)中心地址、以及redis緩存地址和分布式鎖連接等配置項(xiàng)可以通過(guò)修改appsettings.Development.yml配置項(xiàng)自定義指定。

以docker-compose的方式啟動(dòng)和調(diào)試

進(jìn)入到samples目錄下,使用visual studio打開(kāi)lms.samples.dockercompose.sln解決方案,將docker-compose設(shè)置為啟動(dòng)項(xiàng)目,即可啟動(dòng)和調(diào)式。

應(yīng)用啟動(dòng)成功后,打開(kāi): http://127.0.0.1/swagger,即可看到swagger api文檔

以docker-compose的方式啟動(dòng)和調(diào)試,則指定的環(huán)境變量為:ContainerDev

數(shù)據(jù)庫(kù)連接、服務(wù)注冊(cè)中心地址、以及redis緩存地址和分布式鎖連接等配置項(xiàng)可以通過(guò)修改appsettings.ContainerDev.yml配置項(xiàng)自定義指定,配置的服務(wù)連接地址不允許為: 127.0.0.1或是localhost

測(cè)試和調(diào)式

服務(wù)啟動(dòng)成功后,您可以通過(guò)寫(xiě)入/api/account-post接口和/api/product-post新增賬號(hào)和產(chǎn)品,然后通過(guò)/api/order-post接口進(jìn)行測(cè)試和調(diào)式。

開(kāi)源地址

github: https://github.com/liuhll/lms

gitee: https://gitee.com/liuhll2/lms

到此這篇關(guān)于通過(guò)lms.samples熟悉lms微服務(wù)框架的使用的文章就介紹到這了,更多相關(guān)lms微服務(wù)框架內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Markdown語(yǔ)法備忘

    Markdown語(yǔ)法備忘

    Markdown 是一種輕量級(jí)標(biāo)記語(yǔ)言,它允許人們使用易讀易寫(xiě)的純文本格式編寫(xiě)文檔,然后轉(zhuǎn)換成格式豐富的HTML頁(yè)面
    2014-10-10
  • 0基礎(chǔ)租個(gè)硬件玩deepseek,藍(lán)耘元生代智算云|本地部署DeepSeek?R1模型的操作流程

    0基礎(chǔ)租個(gè)硬件玩deepseek,藍(lán)耘元生代智算云|本地部署DeepSeek?R1模型的操作流程

    DeepSeek?R1?模型憑借其強(qiáng)大的自然語(yǔ)言處理能力,在未來(lái)具有廣闊的應(yīng)用前景,有望在多個(gè)領(lǐng)域發(fā)揮重要作用,推動(dòng)各行業(yè)的智能化發(fā)展,文章介紹了如何使用藍(lán)耘元生代智算云在本地部署DeepSeekR1模型,感興趣的朋友一起看看吧
    2025-02-02
  • 最新idea2021最新激活超詳細(xì)教程

    最新idea2021最新激活超詳細(xì)教程

    最近有朋友向小編反應(yīng)idea激活碼失效的問(wèn)題,今天小編給大家推薦使用通過(guò)無(wú)限重置試用期持續(xù)激活,需要的朋友參考下吧
    2020-09-09
  • 后端編程語(yǔ)言多方面對(duì)比:JAVA、C、C++、GO、PYTHON

    后端編程語(yǔ)言多方面對(duì)比:JAVA、C、C++、GO、PYTHON

    軟件開(kāi)發(fā)領(lǐng)域,語(yǔ)言本身在各自領(lǐng)域都有適用場(chǎng)景,有許多流行的編程語(yǔ)言可供選擇,每種語(yǔ)言都有其獨(dú)特的特點(diǎn)和適用場(chǎng)景, Java、Python、Go、C/C++這幾門(mén)語(yǔ)言,主要的應(yīng)用也都在后端開(kāi)發(fā)這里,雖然后端開(kāi)發(fā)是一個(gè)比較明確的方向,但是在后端開(kāi)發(fā)里,也依然可以有很多細(xì)分的領(lǐng)域
    2025-02-02
  • 滑動(dòng)驗(yàn)證碼的設(shè)計(jì)與理解

    滑動(dòng)驗(yàn)證碼的設(shè)計(jì)與理解

    這篇文章主要介紹了滑動(dòng)驗(yàn)證碼的設(shè)計(jì)與理解,本文通過(guò)實(shí)例代碼給大家介紹小網(wǎng)站是怎么設(shè)計(jì)的,代碼簡(jiǎn)單易懂,需要的朋友可以參考下
    2019-08-08
  • Http 狀態(tài)代碼 指示(ajax,bs結(jié)構(gòu)用的到)

    Http 狀態(tài)代碼 指示(ajax,bs結(jié)構(gòu)用的到)

    Http 狀態(tài)代碼主要是方便我們掌握http的一些錯(cuò)誤返回后,知道是什么原因?qū)е碌囊恍﹩?wèn)題,一般結(jié)合監(jiān)聽(tīng)軟件。
    2009-05-05
  • Git分支管理策略

    Git分支管理策略

    這篇文章介紹了Git的分支管理策略,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • XMind?2021激活碼及安裝步驟

    XMind?2021激活碼及安裝步驟

    XMind?是一款非常實(shí)用的商業(yè)思維導(dǎo)圖,應(yīng)用Eclipse?RCP?開(kāi)發(fā)架構(gòu),打造易用、高效的可視化思維,強(qiáng)調(diào)該功能的可擴(kuò)展、跨平臺(tái)、穩(wěn)定性和性能,致力于幫助用戶(hù)提高生產(chǎn)率。本文給大家?guī)?lái)了XMind?2021激活碼,需要的朋友可以參考下
    2021-12-12
  • 關(guān)于最新IDEA2020.2.1,2.2,3以上破解,激活失效,重新激活的問(wèn)題

    關(guān)于最新IDEA2020.2.1,2.2,3以上破解,激活失效,重新激活的問(wèn)題

    今天很多朋友找小編說(shuō)idea2020.2.3版本激活失效了,下面通過(guò)本文給大家分享了最新IDEA2020.2.1,2.2,2.3,idea.3以上破解,激活失效,重新激活的解決方法,需要的朋友參考下吧
    2020-10-10
  • 詳細(xì)介紹HTTP Cookie

    詳細(xì)介紹HTTP Cookie

    本篇文章主要介紹了詳細(xì)介紹HTTP Cookie,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05

最新評(píng)論

永济市| 宜春市| 宜宾县| 泸州市| 惠安县| 师宗县| 开原市| 山东省| 台东县| 修水县| 景洪市| 乌海市| 呼伦贝尔市| 兴海县| 莱阳市| 延边| 漳平市| 江油市| 中江县| 乡城县| 黔西县| 双流县| 海南省| 胶州市| 东山县| 临西县| 吴忠市| 基隆市| 鹤庆县| 资兴市| 连江县| 台北县| 苍梧县| 梧州市| 松原市| 新沂市| 洛浦县| 河南省| 衡阳市| 耿马| 德庆县|