国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

.Net依賴注入神器Scrutor(上)

這篇具有很好參考價(jià)值的文章主要介紹了.Net依賴注入神器Scrutor(上)。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

前言

從.Net Core 開始,.Net 平臺內(nèi)置了一個(gè)輕量,易用的 IOC 的框架,供我們在應(yīng)用程序中使用,社區(qū)內(nèi)還有很多強(qiáng)大的第三方的依賴注入框架如:

  • Autofac
  • DryIOC
  • Grace
  • LightInject
  • Lamar
  • Stashbox
  • Simple Injector

內(nèi)置的依賴注入容器基本可以滿足大多數(shù)應(yīng)用的需求,除非你需要的特定功能不受它支持否則不建議使用第三方的容器。

我們今天介紹的主角Scrutor是內(nèi)置依賴注入的一個(gè)強(qiáng)大的擴(kuò)展,Scrutor有兩個(gè)核心的功能:一是程序集的批量注入 Scanning,二是 Decoration 裝飾器模式,今天的主題是Scanning

開始之前在項(xiàng)目中安裝 nuget 包:

Install-Package Scrutor

學(xué)習(xí)Scrutor前我們先熟悉一個(gè).Net依賴注入的萬能用法。

builder.Services.Add(
    new ServiceDescriptor(/*"ServiceType"*/typeof(ISampleService), /*"implementationType"*/typeof(SampleService), ServiceLifetime.Transient)
    );

第一個(gè)參數(shù)ServiceType通常用接口表示,第二個(gè)implementationType接口的實(shí)現(xiàn),最后生命周期,熟悉了這個(gè)后面的邏輯理解起來就容易些。

Scrutor官方倉庫和本文完整的源代碼在文末

Scanning

Scrutor提供了一個(gè)IServiceCollection的擴(kuò)展方法作為批量注入的入口,該方法提供了Action<ITypeSourceSelector>委托參數(shù)。

builder.Services.Scan(typeSourceSelector => { });

我們所有的配置都是在這個(gè)委托內(nèi)完成的,Setup by Setup 剖析一下這個(gè)使用過程。

第一步 獲取 types

typeSourceSelector 支持程序集反射獲取類型和提供類型參數(shù)

程序集選擇

ITypeSourceSelector有多種獲取程序集的方法來簡化我們選擇程序集


 typeSourceSelector.FromAssemblyOf<Program>();//根據(jù)泛型反射獲取所在的程序集

typeSourceSelector.FromCallingAssembly();//獲取開始發(fā)起調(diào)用方法的程序集

typeSourceSelector.FromEntryAssembly();//獲取應(yīng)用程序入口點(diǎn)所在的程序集

typeSourceSelector.FromApplicationDependencies();//獲取應(yīng)用程序及其依賴項(xiàng)的程序集

typeSourceSelector.FromDependencyContext(DependencyContext.Default);//根據(jù)依賴關(guān)系上下文(DependencyContext)中的運(yùn)行時(shí)庫(Runtime Library)列表。它返回一個(gè)包含了所有運(yùn)行時(shí)庫信息的集合。

typeSourceSelector.FromAssembliesOf(typeof(Program));//根據(jù)類型獲取程序集的集合

typeSourceSelector.FromAssemblies(Assembly.Load("dotNetParadise-Scrutor.dll"));//提供程序集支持Params或者IEnumerable

第二步 從 Types 中選擇 ImplementationType

簡而言之就是從程序中獲取的所有的 types 進(jìn)行過濾,比如獲取的 ImplementationType 必須是非抽象的,是類,是否只需要 Public等,還可以用 ImplementationTypeFilter 提供的擴(kuò)展方法等


builder.Services.Scan(typeSourceSelector =>
{
    typeSourceSelector.FromEntryAssembly().AddClasses();
});

AddClasses()方法默認(rèn)獲取所有公開非抽象的類


還可以通過 AddClasses 的委托參數(shù)來進(jìn)行更多條件的過濾
比如定義一個(gè) Attribute,忽略IgnoreInjectAttribute

namespace dotNetParadise_Scrutor;

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class IgnoreInjectAttribute : Attribute
{
}
builder.Services.Scan(typeSourceSelector =>
{
    typeSourceSelector.FromEntryAssembly().AddClasses(iImplementationTypeFilter =>
    {
        iImplementationTypeFilter.WithoutAttribute<IgnoreInjectAttribute>();
    });
});

利用 iImplementationTypeFilter 的擴(kuò)展方法很簡單就可以實(shí)現(xiàn)

在比如 我只要想實(shí)現(xiàn)IApplicationService接口的類才可以被注入

namespace dotNetParadise_Scrutor;

/// <summary>
/// 依賴注入標(biāo)記接口
/// </summary>
public interface IApplicationService
{
}
builder.Services.Scan(typeSourceSelector =>
{
    typeSourceSelector.FromEntryAssembly().AddClasses(iImplementationTypeFilter =>
    {
        iImplementationTypeFilter.WithoutAttribute<IgnoreInjectAttribute>().AssignableTo<IApplicationService>();
    });
});

類似功能還有很多,如可以根據(jù)命名空間也可以根據(jù)Type的屬性用lambda表達(dá)式對ImplementationType進(jìn)行過濾


上面的一波操作實(shí)際上就是為了構(gòu)造一個(gè)IServiceTypeSelector對象,選出來的ImplementationType對象保存了到了ServiceTypeSelectorTypes屬性中供下一步選擇。
除了提供程序集的方式外還可以直接提供類型的方式比如

創(chuàng)建接口和實(shí)現(xiàn)

public interface IForTypeService
{
}
public class ForTypeService : IForTypeService
{
}
builder.Services.Scan(typeSourceSelector =>
{
    typeSourceSelector.FromTypes(typeof(ForTypeService));
});

這種方式提供類型內(nèi)部會調(diào)用AddClass()方法把符合條件的參數(shù)保存到ServiceTypeSelector

第三步確定注冊策略

AddClass之后可以調(diào)用UsingRegistrationStrategy()配置注冊策略是 Append,Skip,ThrowReplace
下面是各個(gè)模式的詳細(xì)解釋

  • RegistrationStrategy.Append :類似于builder.Services.Add
  • RegistrationStrategy.Skip:類似于builder.Services.TryAdd
  • RegistrationStrategy.Throw:ServiceDescriptor 重復(fù)則跑異常
  • RegistrationStrategy.Replace: 替換原有服務(wù)

這樣可以靈活地控制注冊流程

    builder.Services.Scan(typeSourceSelector =>
    {
        typeSourceSelector.FromEntryAssembly().AddClasses().UsingRegistrationStrategy(RegistrationStrategy.Skip);
    });

不指定則為默認(rèn)的 Append 即 builder.Services.Add

第四步 配置注冊的場景選擇合適的ServiceType

ServiceTypeSelector提供了多種方法讓我們從ImplementationType中匹配ServiceType

  • AsSelf()
  • As<T>()
  • As(params Type[] types)
  • As(IEnumerable<Type> types)
  • AsImplementedInterfaces()
  • AsImplementedInterfaces(Func<Type, bool> predicate)
  • AsSelfWithInterfaces()
  • AsSelfWithInterfaces(Func<Type, bool> predicate)
  • AsMatchingInterface()
  • AsMatchingInterface(Action<Type, IImplementationTypeFilter>? action)
  • As(Func<Type, IEnumerable<Type>> selector)
  • UsingAttributes()

AsSelf 注冊自身

public class AsSelfService
{
}
{
    builder.Services.Scan(typeSourceSelector =>
    {
        typeSourceSelector.FromEntryAssembly().AddClasses(iImplementationTypeFilter =>
        {
            iImplementationTypeFilter.InNamespaces("dotNetParadise_Scrutor.Application.AsSelf").WithoutAttribute<IgnoreInjectAttribute>();
        }).AsSelf();
    });

    Debug.Assert(builder.Services.Any(_ => _.ServiceType == typeof(AsSelfService)));
}

等效于builder.Services.AddTransient<AsSelfService>();


As 批量為 ImplementationType 指定 ServiceType

public interface IAsService
{
}
public class AsOneService : IAsService
{
}
public class AsTwoService : IAsService
{
}
{
    builder.Services.Scan(typeSourceSelector =>
{
    typeSourceSelector.FromEntryAssembly().AddClasses(iImplementationTypeFilter =>
    {
        iImplementationTypeFilter.InNamespaces("dotNetParadise_Scrutor.Application.As").WithoutAttribute<IgnoreInjectAttribute>();
    }).As<IAsService>();
});
    Debug.Assert(builder.Services.Any(_ => _.ServiceType == typeof(IAsService)));
    foreach (var asService in builder.Services.Where(_ => _.ServiceType == typeof(IAsService)))
    {
        Debug.WriteLine(asService.ImplementationType!.Name);
    }
}

As(params Type[] types)和 As(IEnumerable types) 批量為ImplementationType指定多個(gè) ServiceType,服務(wù)必須同時(shí)實(shí)現(xiàn)這里面的所有的接口

上面的實(shí)例再改進(jìn)一下

public interface IAsOtherService
{
}
public interface IAsSomeService
{
}

public class AsOneMoreTypesService : IAsOtherService, IAsSomeService
{
}
public class AsTwoMoreTypesService : IAsSomeService, IAsOtherService
{
}

{
    builder.Services.Scan(typeSourceSelector =>
    {
        typeSourceSelector.FromEntryAssembly().AddClasses(iImplementationTypeFilter =>
        {
            iImplementationTypeFilter.InNamespaces("dotNetParadise_Scrutor.Application.AsMoreTypes").WithoutAttribute<IgnoreInjectAttribute>();
        }).As(typeof(IAsSomeService), typeof(IAsOtherService));
    });
    List<Type> serviceTypes = [typeof(IAsSomeService), typeof(IAsOtherService)];
    Debug.Assert(serviceTypes.All(serviceType => builder.Services.Any(service => service.ServiceType == serviceType)));
    foreach (var asService in builder.Services.Where(_ => _.ServiceType == typeof(IAsSomeService) || _.ServiceType == typeof(IAsOtherService)))
    {
        Debug.WriteLine(asService.ImplementationType!.Name);
    }
}

AsImplementedInterfaces 注冊當(dāng)前 ImplementationType 和實(shí)現(xiàn)的接口

public interface IAsImplementedInterfacesService
{
}
public class AsImplementedInterfacesService : IAsImplementedInterfacesService
{
}
//AsImplementedInterfaces 注冊當(dāng)前ImplementationType和它實(shí)現(xiàn)的接口
{
    builder.Services.Scan(typeSourceSelector =>
    {
        typeSourceSelector.FromEntryAssembly().AddClasses(iImplementationTypeFilter =>
        {
            iImplementationTypeFilter.InNamespaces("dotNetParadise_Scrutor.Application.AsImplementedInterfaces").WithoutAttribute<IgnoreInjectAttribute>();
        }).AsImplementedInterfaces();
    });

    Debug.Assert(builder.Services.Any(service => service.ServiceType == typeof(IAsImplementedInterfacesService)));
    foreach (var asService in builder.Services.Where(_ => _.ServiceType == typeof(IAsImplementedInterfacesService)))
    {
        Debug.WriteLine(asService.ImplementationType!.Name);
    }
}

AsSelfWithInterfaces 同時(shí)注冊為自身類型和所有實(shí)現(xiàn)的接口

public interface IAsSelfWithInterfacesService
{
}
public class AsSelfWithInterfacesService : IAsSelfWithInterfacesService
{
}

{
    builder.Services.Scan(typeSourceSelector =>
    {
        typeSourceSelector.FromEntryAssembly().AddClasses(iImplementationTypeFilter =>
        {
            iImplementationTypeFilter.InNamespaces("dotNetParadise_Scrutor.Application.AsSelfWithInterfaces").WithoutAttribute<IgnoreInjectAttribute>();
        }).AsSelfWithInterfaces();
    });
    //Self
    Debug.Assert(builder.Services.Any(service => service.ServiceType == typeof(AsSelfWithInterfacesService)));
    //Interfaces
    Debug.Assert(builder.Services.Any(service => service.ServiceType == typeof(IAsSelfWithInterfacesService)));
    foreach (var service in builder.Services.Where(_ => _.ServiceType == typeof(AsSelfWithInterfacesService) || _.ServiceType == typeof(IAsSelfWithInterfacesService)))
    {
        Debug.WriteLine(service.ServiceType!.Name);
    }
}

AsMatchingInterface 將服務(wù)注冊為與其命名相匹配的接口,可以理解為一定約定假如服務(wù)名稱為 ClassName,會找 IClassName 的接口作為 ServiceType 注冊

public interface IAsMatchingInterfaceService
{
}
public class AsMatchingInterfaceService : IAsMatchingInterfaceService
{
}
//AsMatchingInterface 將服務(wù)注冊為與其命名相匹配的接口,可以理解為一定約定假如服務(wù)名稱為 ClassName,會找 IClassName 的接口作為 ServiceType 注冊
{
    builder.Services.Scan(typeSourceSelector =>
    {
        typeSourceSelector.FromEntryAssembly().AddClasses(iImplementationTypeFilter =>
        {
            iImplementationTypeFilter.InNamespaces("dotNetParadise_Scrutor.Application.AsMatchingInterface").WithoutAttribute<IgnoreInjectAttribute>();
        }).AsMatchingInterface();
    });
    Debug.Assert(builder.Services.Any(service => service.ServiceType == typeof(IAsMatchingInterfaceService)));
    foreach (var service in builder.Services.Where(_ => _.ServiceType == typeof(IAsMatchingInterfaceService)))
    {
        Debug.WriteLine(service.ServiceType!.Name);
    }
}

UsingAttributes 特性注入,這個(gè)還是很實(shí)用的在Scrutor提供了ServiceDescriptorAttribute來幫助我們方便的對Class進(jìn)行標(biāo)記方便注入

public interface IUsingAttributesService
{
}

[ServiceDescriptor<IUsingAttributesService>()]
public class UsingAttributesService : IUsingAttributesService
{
}
    builder.Services.Scan(typeSourceSelector =>
    {
        typeSourceSelector.FromEntryAssembly().AddClasses(iImplementationTypeFilter =>
        {
            iImplementationTypeFilter.InNamespaces("dotNetParadise_Scrutor.Application.UsingAttributes").WithoutAttribute<IgnoreInjectAttribute>();
        }).UsingAttributes();
    });
    Debug.Assert(builder.Services.Any(service => service.ServiceType == typeof(IUsingAttributesService)));
    foreach (var service in builder.Services.Where(_ => _.ServiceType == typeof(IUsingAttributesService)))
    {
        Debug.WriteLine(service.ServiceType!.Name);
    }

第五步 配置生命周期

通過鏈?zhǔn)秸{(diào)用WithLifetime函數(shù)來確定我們的生命周期,默認(rèn)是 Transient

public interface IFullService
{
}
public class FullService : IFullService
{
}
{

    builder.Services.Scan(typeSourceSelector =>
    {
        typeSourceSelector.FromEntryAssembly().AddClasses(iImplementationTypeFilter =>
        {
            iImplementationTypeFilter.InNamespaces("dotNetParadise_Scrutor.Application.Full");
        }).UsingRegistrationStrategy(RegistrationStrategy.Skip).AsImplementedInterfaces().WithLifetime(ServiceLifetime.Scoped);
    });

    Debug.Assert(builder.Services.Any(service => service.ServiceType == typeof(IFullService)));
    foreach (var service in builder.Services.Where(_ => _.ServiceType == typeof(IFullService)))
    {
        Debug.WriteLine($"serviceType:{service.ServiceType!.Name},LifeTime:{service.Lifetime}");
    }
}

總結(jié)

到這兒基本的功能已經(jīng)介紹完了,可以看出來擴(kuò)展方法很多,基本可以滿足開發(fā)過程批量依賴注入的大部分場景。
使用技巧總結(jié):

  • 根據(jù)程序集獲取所有的類型 此時(shí) Scrutor 會返回一個(gè) IImplementationTypeSelector 對象里面包含了程序集的所有類型集合
  • 調(diào)用 IImplementationTypeSelectorAddClasses 方法獲取 IServiceTypeSelector 對象,AddClass 這里面可以根據(jù)條件選擇 過濾一些不需要的類型
  • 調(diào)用UsingRegistrationStrategy確定依賴注入的策略 是覆蓋 還是跳過亦或是拋出異常 默認(rèn) Append 追加注入的方式
  • 配置注冊的場景 比如是 AsImplementedInterfaces 還是 AsSelf
  • 選擇生命周期 默認(rèn) Transient

借助ServiceDescriptorAttribute更簡單,生命周期和ServiceType都是在Attribute指定好的只需要確定選擇程序集,調(diào)用UsingRegistrationStrategy配置依賴注入的策略然后UsingAttributes()即可

最后

本文從Scrutor的使用流程剖析了依賴注入批量注冊的流程,更詳細(xì)的教程可以參考Github 官方倉庫。在開發(fā)過程中看到很多項(xiàng)目還有一個(gè)個(gè)手動注入的,也有自己寫 Interface或者是Attribute反射注入的,支持的場景都十分有限,Scrutor的出現(xiàn)就是為了避免我們在項(xiàng)目中不停地造輪子,達(dá)到開箱即用的目的。

本文完整示例源代碼文章來源地址http://www.zghlxwxcb.cn/news/detail-841372.html

到了這里,關(guān)于.Net依賴注入神器Scrutor(上)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • .NET 通過源碼深究依賴注入原理

    .NET 通過源碼深究依賴注入原理

    依賴注入 (DI) 是.NET中一個(gè)非常重要的軟件設(shè)計(jì)模式,它可以幫助我們更好地管理和組織組件,提高代碼的可讀性,擴(kuò)展性和可測試性。在日常工作中,我們一定遇見過這些問題或者疑惑。 Singleton服務(wù)為什么不能依賴Scoped服務(wù)? 多個(gè)構(gòu)造函數(shù)的選擇機(jī)制? 源碼是如何識別循環(huán)

    2024年02月05日
    瀏覽(30)
  • 從零開始 Spring Boot 38:Lombok 與依賴注入

    從零開始 Spring Boot 38:Lombok 與依賴注入

    圖源:簡書 (jianshu.com) 在之前的文章中,我詳細(xì)介紹了 Lombok 的用法,考慮到在 Spring 中使用依賴注入(DI)是如此的頻繁,因此有必要討論使用 Lombok 時(shí)可能對依賴注入造成的影響。 我們都知道,Spring 中的依賴注入分為三種情況: 通過屬性進(jìn)行依賴注入。 通過構(gòu)造器進(jìn)行依

    2024年02月08日
    瀏覽(37)
  • .NET 6 整合 Autofac 依賴注入容器

    一行業(yè)務(wù)代碼還沒寫,框架代碼一大堆,不利于學(xué)習(xí)。 ??吹絡(luò)ava的學(xué)習(xí)資料或博客,標(biāo)題一般為《SpringBoot 整合 XXX》,所以仿照著寫了《.NET 6 整合 Autofac 依賴注入容器》這樣一個(gè)標(biāo)題。 以下是我自己的用法,可能不是最佳實(shí)踐。 NuGet搜索并安裝: Autofac Autofac.Extensions.Depe

    2023年04月26日
    瀏覽(29)
  • .Net Framework使用Autofac實(shí)現(xiàn)依賴注入

    最近也是找了快2周的工作了,收到的面試邀請也就幾個(gè),然后有個(gè)面試題目是用asp.net mvc + Entityframework 做一個(gè)學(xué)生信息增刪改查系統(tǒng)。因?yàn)轭}目要求了用Entityframework 也就是EF 那也就不上core了,web項(xiàng)目也是用Framework 4.8去做的。 本文的重點(diǎn)是IOC容器,在Framework 中是沒有自帶的

    2024年02月09日
    瀏覽(18)
  • .Net6 使用Autofac進(jìn)行依賴注入

    剛接觸.net 6,記錄一下在.net6上是怎么使用Autofac進(jìn)行動態(tài)的依賴注入的 1、新建一個(gè)webapi項(xiàng)目,框架選擇net 6 2、引用Nuget包---Autofac.Extensions.Dependency 3、在Program.cs上添加如下代碼 4. 或 以及再startup.cs中添加ConfigureContainer方法 ? ?public void ConfigureContainer(ContainerBuilder builder) ? ?

    2024年04月11日
    瀏覽(19)
  • .Net6.0系列-7 依賴注入(一)

    依賴注入(Dependency Injection,DI)是控制反轉(zhuǎn)(Inversion of Control,IOC)思想的實(shí)現(xiàn)方式,依賴注入簡化模塊的組裝過程,降低模塊之間的耦合度. DI的幾個(gè)概念: 服務(wù)(Service):和框架請求之后返回的一個(gè)對象,可以是一個(gè)數(shù)據(jù)庫鏈接,也可以是一個(gè)文件處理的方法,或者是數(shù)據(jù)處理的一個(gè)過程方法

    2023年04月11日
    瀏覽(21)
  • ASP.NET Core 依賴注入系列一

    ASP.NET Core 依賴注入系列一

    什么是ASP.NET Core 依賴注入? 依賴注入也稱DI是一項(xiàng)技術(shù)用來實(shí)現(xiàn)對象松耦合以至于應(yīng)用程序更容易維護(hù),ASP.NET Core通過控制器的構(gòu)造函數(shù)自動注入依賴的對象,我們創(chuàng)建ASP.NET Core MVC應(yīng)用程序演示依賴注入特性是如何工作, 在這節(jié)中我們講解該特性 1 例子 我們創(chuàng)建一個(gè)ASP.NET C

    2024年02月11日
    瀏覽(98)
  • ASP.NET WebApi 極簡依賴注入

    ASP.NET WebApi 極簡依賴注入

    .NET Core 7.0 ASP.NET Core Visual Studio 2022 .Net Core WebApi Redis消息訂閱 ASP.NET Core 依賴注入最佳實(shí)踐 簡單來說就是 有效地設(shè)計(jì)服務(wù)及其依賴關(guān)系。 防止多線程問題。 防止內(nèi)存泄漏。 防止?jié)撛诘腻e(cuò)誤。

    2024年02月08日
    瀏覽(94)
  • 【C#/.NET】MAUI上的依賴注入

    【C#/.NET】MAUI上的依賴注入

    ? ????????在移動應(yīng)用開發(fā)中,依賴注入是一項(xiàng)非常重要的技術(shù),它可以幫助我們簡化代碼結(jié)構(gòu)、提高可維護(hù)性并增加測試覆蓋率。在最新的.NET跨平臺框架MAUI中,我們也可以利用依賴注入來構(gòu)建高效的應(yīng)用程序架構(gòu)。本文將詳細(xì)介紹在MAUI上如何使用依賴注入,旨在幫助

    2024年02月11日
    瀏覽(25)
  • 【微軟技術(shù)?!緾#.NET 依賴項(xiàng)注入

    多個(gè)構(gòu)造函數(shù)發(fā)現(xiàn)規(guī)則 使用擴(kuò)展方法注冊服務(wù)組 框架提供的服務(wù) 服務(wù)生存期 服務(wù)注冊方法 作用域驗(yàn)證 范圍場景 .NET 支持依賴關(guān)系注入 (DI) 軟件設(shè)計(jì)模式,這是一種在類及其依賴項(xiàng)之間實(shí)現(xiàn)控制反轉(zhuǎn) (IoC)?的技術(shù)。 .NET 中的依賴關(guān)系注入是框架的內(nèi)置部分,與配置、日志記

    2024年02月03日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包