.net core2.0下Ioc容器Autofac使用

来源:https://www.cnblogs.com/yanweidie/archive/2018/03/28/autofac.html
-Advertisement-
Play Games

.net core發佈有一段時間了,最近兩個月開始使用.net core2.0開發項目,大大小小遇到了一些問題。準備寫個系列介紹一下是如何解決這些問題以及對應技術。先從IOC容器Autofac開始該系列。 閱讀目錄 Autofac基本使用 .net core MVC與Autofac 屬性註入 Aut ...


  .net core發佈有一段時間了,最近兩個月開始使用.net core2.0開發項目,大大小小遇到了一些問題。準備寫個系列介紹一下是如何解決這些問題以及對應技術。先從IOC容器Autofac開始該系列。

閱讀目錄

回到頂部

Autofac基本使用

  Autofac是一款輕量級的IOC框架,使用率上還是挺高的,官方網站http://autofac.org,源碼下載地址https://github.com/autofac/Autofac

  下麵以狗的列子來介紹autofac,nuget搜索Autofac進行安裝

    public interface IDog
    {
        /// <summary>
        /// 品種
        /// </summary>
        string Breed { get; }

        /// <summary>
        /// 名稱
        /// </summary>
        string Name { get; }
    }

    /// <summary>
    /// 薩摩耶
    /// </summary>
    public class Samoyed : IDog
    {
        /// <summary>
        /// 品種
        /// </summary>
        public string Breed
        {
            get
            {
                return "Samoyed(薩摩耶)";
            }
        }

        /// <summary>
        /// 名稱
        /// </summary>
        public string Name
        {
            get
            {
                return "小黃";
            }
        }
    }

    /// <summary>
    /// 藏獒
    /// </summary>
    public class TibetanMastiff : IDog
    {
        /// <summary>
        /// 品種
        /// </summary>
        public string Breed
        {
            get
            {
                return "Mastiff Class(獒犬類)";
            }
        }

        /// <summary>
        /// 名稱
        /// </summary>
        public string Name
        {
            get
            {
                return "小黑";
            }
        }
    }
View Code

  1.RegisterType 

public static void Register()
{
    var builder = new ContainerBuilder();
    //註冊Samoyed指定為IDog實現
    builder.RegisterType<Samoyed>().As<IDog>();
    builder.RegisterType<TibetanMastiff>().As<IDog>();
    using (var container = builder.Build())
    {
        var dogs = container.Resolve<IEnumerable<IDog>>();
        foreach (var dog in dogs)
        {
             Console.WriteLine($"名稱:{dog.Name},品種:{dog.Breed}");
        }
    }
}        
  2.RegisterAssemblyTypes
public static void RegisterAssemblyTypes()
{
    var builder = new ContainerBuilder();
    //註冊程式集下所有類型
    builder.RegisterAssemblyTypes(typeof(Program).Assembly).AsImplementedInterfaces();
    using (var container = builder.Build())
    {
        var dogs = container.Resolve<IEnumerable<IDog>>();
        foreach (var dog in dogs)
        {
            Console.WriteLine($"名稱:{dog.Name},品種:{dog.Breed}");
        }
    }
}

  直接註冊程式集下的所有類型,AsImplementedInterfaces(讓具體實現類型,可以該類型繼承的所有介面類型找到該實現類型)

  3.RegisterInstance

TibetanMastiff d = new TibetanMastiff();
builder.RegisterInstance(d).As<IDog>();

  4.RegisterModule

  這種模式需要使用配置文件進行註冊,個人更喜歡代碼直接註冊的方式,畢竟配置文件修改容易遺忘和出錯。這裡就不介紹該方式了。 

      

  遺留問題:上面的註冊代碼,自己寫寫demo的時候沒啥問題。但是運用到項目裡面就很繁瑣了,需要自己一個個類型註冊,後面會提供解決方案。

回到頂部  

.net core MVC與Autofac

  1.首先nuget下載AutofacAutofac.Extensions.DependencyInjection引用

  2.替換mvc自帶的DI框架

  將Startup.cs中的ConfigureServices返回類型改為IServiceProvider

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    var builder = new ContainerBuilder();
    builder.Populate(services);
    builder.RegisterAssemblyTypes(typeof(Startup).Assembly).AsImplementedInterfaces();
    var Container = builder.Build();
    return new AutofacServiceProvider(Container);
}
回到頂部

屬性註入

Autofac預設是構造函數註入

[Route("api/[controller]")]
public class ValuesController : Controller
{
    private readonly IEnumerable<IDog> dogs;

    public ValuesController(IEnumerable<IDog> _dogs)
    {
        dogs = _dogs;
    }

    // GET api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        List<string> list = new List<string>();
        foreach (var dog in dogs)
        {
            list.Add($"名稱:{dog.Name},品種:{dog.Breed}");
        }
        return list.ToArray(); ;
    }
}
  使用過mef的可能更喜歡屬性註入的方式,那麼使用autofac怎麼實現屬性註入呢? 1.註冊系統所有Controller,由Autofac創建
var IControllerType = typeof(ControllerBase);
builder.RegisterAssemblyTypes(assembly).Where(t => 
                IControllerType.IsAssignableFrom(t) && t != IControllerType).PropertiesAutowired();

 上面這段代碼的解釋:註冊所有程式集下繼承ControllerBase的類型,PropertiesAutowired 允許屬性註入。

2.替換系統預設Controller創建器

services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
services.AddMvc();
註意:Replace代碼放在AddMvc之前 Replace代碼的意思:使用ServiceBasedControllerActivator替換DefaultControllerActivator(意味著框架現在會嘗試從IServiceProvider中解析控制器實例,也就是return new AutofacServiceProvider(Container);
3.使用屬性註入
  [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        public IEnumerable<IDog> dogs { get; set; }
        [HttpGet]
        public IEnumerable<string> Get()
        {
            List<string> list = new List<string>();
            foreach (var dog in dogs)
            {
                list.Add($"名稱:{dog.Name},品種:{dog.Breed}");
            }
            return list.ToArray(); ;
        }
    }
至此完成了使用Autofac實現屬性註入 回到頂部

Autofac+Castle實現AOP

1.首先nuget下載Autofac.Extras.DynamicProxy引用 2.編寫攔截器
public class LogInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Console.WriteLine("你正在調用方法 \"{0}\"  參數是 {1}... ",
           invocation.Method.Name,
           string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()));

        invocation.Proceed();
        if (invocation.ReturnValue != null && invocation.ReturnValue is string)
        {
            //在返回介面上拼上LogInterceptor
            invocation.ReturnValue += " LogInterceptor";
        }
        Console.WriteLine("方法執行完畢,返回結果:{0}", invocation.ReturnValue);

        Console.WriteLine("開始記錄日誌....");
    }
}
3.開啟攔截(介面攔截器  類攔截器)
builder.RegisterType<LogInterceptor>();
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces() .EnableInterfaceInterceptors();
var IControllerType = typeof(ControllerBase); builder.RegisterAssemblyTypes(assembly).Where(t => IControllerType.IsAssignableFrom(t) && t != IControllerType).PropertiesAutowired() .EnableClassInterceptors(); var Container = builder.Build();
開啟介面攔截器:EnableInterfaceInterceptors  開啟類攔截器:EnableClassInterceptors
[Intercept(typeof(LogInterceptor))]
[Route("api/[controller]")]
public class ValuesController : Controller
{
}
[Intercept(typeof(LogInterceptor))]
public class Samoyed : IDog
{
}
這種使用方式需要自己指定在哪個類上使用,還有一種全局攔截器
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces().EnableInterfaceInterceptors()
.InterceptedBy(
typeof(LogInterceptor));

 

回到頂部

代碼封裝簡單使用

先列出使用過程中遇到的幾個問題,然後再給出解決方案

1:如何簡單註冊代碼裡面的所有類型

2.如何註冊單例和普通對象

3.封裝好的代碼怎麼支持用戶特殊化註冊需求

為瞭解決上述問題,這裡給出了幾個約束

單例對象需繼承的介面:ISingletonDependency  普通對象需繼承的介面:ITransientDependency 特殊化註冊介面:IDependencyRegistrar

通過這幾個約束,在初始化時找所有程式集 繼承ISingletonDependency ,ITransientDependency 介面的對象進行類型註冊

    /// <summary>
    /// 單例介面
    /// </summary>
    public interface ISingletonDependency
    {
    }
    /// <summary>
    /// 所有介面的依賴介面,每次創建新實例
    /// </summary>
    /// <remarks>
    /// 用於Autofac自動註冊時,查找所有依賴該介面的實現。
    /// 實現自動註冊功能
    /// </remarks>
    public interface ITransientDependency
    {
    }

 

    /// <summary>
    /// 依賴註冊介面
    /// </summary>
    public interface IDependencyRegistrar
    {
        /// <summary>
        /// Register services and interfaces
        /// </summary>
        /// <param name="builder">Container builder</param>
        /// <param name="config">Config</param>
        void Register(ContainerBuilder builder,List<Type> listType);

        /// <summary>
        /// Order of this dependency registrar implementation
        /// </summary>
        int Order { get; }
    }

 

 public interface IIocManager
    {
        IContainer Container { get; }

        bool IsRegistered(Type serviceType, ILifetimeScope scope = null);
        object Resolve(Type type, ILifetimeScope scope = null);
        T Resolve<T>(string key = "", ILifetimeScope scope = null) where T : class;
        T Resolve<T>(params Parameter[] parameters) where T : class;
        T[] ResolveAll<T>(string key = "", ILifetimeScope scope = null);
        object ResolveOptional(Type serviceType, ILifetimeScope scope = null);
        object ResolveUnregistered(Type type, ILifetimeScope scope = null);
        T ResolveUnregistered<T>(ILifetimeScope scope = null) where T : class;
        ILifetimeScope Scope();
        bool TryResolve(Type serviceType, ILifetimeScope scope, out object instance);
    }
/// <summary>
    /// Container manager
    /// </summary>
    public class IocManager : IIocManager
    {
        private IContainer _container;

        public static IocManager Instance { get { return SingletonInstance; } }
        private static readonly IocManager SingletonInstance = new IocManager();

        /// <summary>
        /// Ioc容器初始化
        /// </summary>
        /// <param name="config"></param>
        /// <returns></returns>
        public IServiceProvider Initialize(IServiceCollection services)
        {
            var builder = new ContainerBuilder();
            builder.RegisterInstance(Instance).As<IIocManager>().SingleInstance();
            //所有程式集 和程式集下類型
            var deps = DependencyContext.Default;
            var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != "package");//排除所有的系統程式集、Nuget下載包
            var listAllType = new List<Type>();
            foreach (var lib in libs)
            {
                try
                {
                    var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));
                    listAllType.AddRange(assembly.GetTypes().Where(type => type != null));
                }
                catch { }
            }
            //找到所有外部IDependencyRegistrar實現,調用註冊
            var registrarType = typeof(IDependencyRegistrar);
            var arrRegistrarType = listAllType.Where(t => registrarType.IsAssignableFrom(t) && t != registrarType).ToArray();
            var listRegistrarInstances = new List<IDependencyRegistrar>();
            foreach (var drType in arrRegistrarType)
            {
                listRegistrarInstances.Add((IDependencyRegistrar)Activator.CreateInstance(drType));
            }
            //排序
            listRegistrarInstances = listRegistrarInstances.OrderBy(t => t.Order).ToList();
            foreach (var dependencyRegistrar in listRegistrarInstances)
            {
                dependencyRegistrar.Register(builder, listAllType);
            }

            //註冊ITransientDependency實現類
            var dependencyType = typeof(ITransientDependency);
            var arrDependencyType = listAllType.Where(t => dependencyType.IsAssignableFrom(t) && t != dependencyType).ToArray();
            builder.RegisterTypes(arrDependencyType)
                .AsImplementedInterfaces()
                .InstancePerLifetimeScope()
                .PropertiesAutowired().EnableInterfaceInterceptors();

            foreach (Type type in arrDependencyType)
            {
                if (type.IsClass && !type.IsAbstract && !type.BaseType.IsInterface && type.BaseType != typeof(object))
                {
                    builder.RegisterType(type).As(type.BaseType)
                        .InstancePerLifetimeScope()
                        .PropertiesAutowired();
                }
            }


            //註冊ISingletonDependency實現類
            var singletonDependencyType = typeof(ISingletonDependency);
            var arrSingletonDependencyType = listAllType.Where(t => singletonDependencyType.IsAssignableFrom(t) && t != singletonDependencyType).ToArray();
            builder.RegisterTypes(arrSingletonDependencyType)
                .AsImplementedInterfaces()
                .SingleInstance()
                .PropertiesAutowired();

            foreach (Type type in arrSingletonDependencyType)
            {
                if (type.IsClass && !type.IsAbstract && !type.BaseType.IsInterface && type.BaseType != typeof(object))
                {
                    builder.RegisterType(type).As(type.BaseType)
                        .SingleInstance()
                        .PropertiesAutowired();
                }
            }

            builder.Populate(services);
            _container = builder.Build();
            return new AutofacServiceProvider(_container);
        }

        /// <summary>
        /// Gets a container
        /// </summary>
        public virtual IContainer Container
        {
            get
            {
                return _container;
            }
        }

        /// <summary>
        /// Resolve
        /// </summary>
        /// <typeparam name="T">Type</typeparam>
        /// <param name="key">key</param>
        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
        /// <returns>Resolved service</returns>
        public virtual T Resolve<T>(string key = "", ILifetimeScope scope = null) where T : class
        {
            if (scope == null)
            {
                //no scope specified
                scope = Scope();
            }
            if (string.IsNullOrEmpty(key))
            {
                return scope.Resolve<T>();
            }
            return scope.ResolveKeyed<T>(key);
        }

        /// <summary>
        /// Resolve
        /// </summary>
        /// <typeparam name="T">Type</typeparam>
        /// <param name="key">key</param>
        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
        /// <returns>Resolved service</returns>
        public virtual T Resolve<T>(params Parameter[] parameters) where T : class
        {
            var scope = Scope();
            return scope.Resolve<T>(parameters);
        }

        /// <summary>
        /// Resolve
        /// </summary>
        /// <param name="type">Type</param>
        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
        /// <returns>Resolved service</returns>
        public virtual object Resolve(Type type, ILifetimeScope scope = null)
        {
            if (scope == null)
            {
                //no scope specified
                scope = Scope();
            }
            return scope.Resolve(type);
        }

        /// <summary>
        /// Resolve all
        /// </summary>
        /// <typeparam name="T">Type</typeparam>
        /// <param name="key">key</param>
        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
        /// <returns>Resolved services</returns>
        public virtual T[] ResolveAll<T>(string key = "", ILifetimeScope scope = null)
        {
            if (scope == null)
            {
                //no scope specified
                scope = Scope();
            }
            if (string.IsNullOrEmpty(key))
            {
                return scope.Resolve<IEnumerable<T>>().ToArray();
            }
            return scope.ResolveKeyed<IEnumerable<T>>(key).ToArray();
        }

        /// <summary>
        /// Resolve unregistered service
        /// </summary>
        /// <typeparam name="T">Type</typeparam>
        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
        /// <returns>Resolved service</returns>
        public virtual T ResolveUnregistered<T>(ILifetimeScope scope = null) where T : class
        {
            return ResolveUnregistered(typeof(T), scope) as T;
        }

        /// <summary>
        /// Resolve unregistered service
        /// </summary>
        /// <param name="type">Type</param>
        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
        /// <returns>Resolved service</returns>
        public virtual object ResolveUnregistered(Type type, ILifetimeScope scope = null)
        {
            if (scope == null)
            {
                //no scope specified
                scope = Scope();
            }
            var constructors = type.GetConstructors();
            foreach (var constructor in constructors)
            {
                try
                {
                    var parameters = constructor.GetParameters();
                    var parameterInstances = new List<object>();
                    foreach (var parameter in parameters)
                    {
                        var service = Resolve(parameter.ParameterType, scope);
                        if (service == null) throw new Exception("Unknown dependency");
                        parameterInstances.Add(service);
                    }
                    return Activator.CreateInstance(type, parameterInstances.ToArray());
                }
                catch (Exception)
                {

                }
            }
            throw new Exception("No constructor  was found that had all the dependencies satisfied.");
        }

        /// <summary>
        /// Try to resolve srevice
        /// </summary>
        /// <param name="serviceType">Type</param>
        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
        /// <param name="instance">Resolved service</param>
        /// <returns>Value indicating whether service has been successfully resolved</returns>
        public virtual bool TryResolve(Type serviceType, ILifetimeScope scope, out object instance)
        {
            if (scope == null)
            {
                //no scope specified
                scope = Scope();
            }
            return scope.TryResolve(serviceType, out instance);
        }

        /// <summary>
        /// Check whether some service is registered (can be resolved)
        /// </summary>
        /// <param name="serviceType">Type</param>
        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
        /// <returns>Result</returns>
        public virtual bool IsRegistered(Type serviceType, ILifetimeScope scope = null)
        {
            if (scope == null)
            {
                //no scope specified
                scope = Scope();
            }
            return scope.IsRegistered(serviceType);
        }

        /// <summary>
        /// Resolve optional
        /// </summary>
        /// <param name="serviceType">Type</param>
        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>
        /// <returns>Resolved service</returns>
        public virtual object ResolveOptional(Type serviceType, ILifetimeScope scope = null)
        {
            if (scope == null)
            {
                //no scope specified
                scope = Scope();
            }
            return scope.ResolveOptional(serviceType);
        }

        /// <summary>
        /// Get current scope
        /// </summary>
        /// <returns>Scope</returns>
        public virtual ILifetimeScope Scope()
        {
            try
            {
                //when such lifetime scope is returned, you should be sure that it'll be disposed once used (e.g. in schedule tasks)
                return Container.BeginLifetimeScope();
            }
            catch (Exception)
            {
                //we can get an exception here if RequestLifetimeScope is already disposed
                //for example, requested in or after "Application_EndRequest" handler
                //but note that usually it should never happen

                //when such lifetime scope is returned, you should be sure that it'll be disposed once used (e.g. in schedule tasks)
                return Container.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
            }
        }
    }
使用介紹
       public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
            services.AddMvc();
            return IocManager.Instance.Initialize(services);
        }
回到頂部

特殊場景介紹

通過上面的封裝後,我們可以把Controller的註冊單獨出來

    /// <summary>
    /// 
    /// </summary>
    public class ControllerRegistrar : IDependencyRegistrar
    {
        /// <summary>
        /// 
        /// </summary>
        public int Order
        {
            get
            {
                return 0;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="listType"></param>
        public void Register(ContainerBuilder builder, List<Type> listType)
        {
            builder.RegisterType(typeof(LogInterceptor));
            //註冊Controller,實現屬性註入
            var IControllerType = typeof(ControllerBase);
            var arrControllerType = listType.Where(t => IControllerType.IsAssignableFrom(t) && t != IControllerType).ToArray();
            builder.RegisterTypes(arrControllerType).PropertiesAutowired().EnableClassInterceptors();
        }
    }
下麵介紹幾種特殊使用方式 1.創建實例時給指定參數賦值
builder.RegisterType(typeof(TestDemo)).AsSelf();
  
public class TestDemo
    {
        
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • "&&","||"邏輯重載操作符的缺陷 大家,都知道"&&","||"擁有"短路"功能 比如a=(0&&b) : 由於第一個操作數為0,所以不會去判斷b的內容,直接執行a=0 比如a=(-100||b): 由於-100不為0,所以不會去判斷b的內容,直接執行a=1 可以參考下麵代碼: 運行列印: 並 ...
  • 後端開發:1、高級java軟體架構師實戰培訓視頻教程2、大型SpringMVC,Mybatis,Redis,Solr,Nginx,SSM分散式電商項目視頻教程3、Spark Streaming實時流處理項目實戰4、Java校招面試 Google面試官親授5、Java開發企業級許可權管理系統6、Java ...
  • 後端開發:1、高級java軟體架構師實戰培訓視頻教程2、大型SpringMVC,Mybatis,Redis,Solr,Nginx,SSM分散式電商項目視頻教程3、Spark Streaming實時流處理項目實戰4、Java校招面試 Google面試官親授5、Java開發企業級許可權管理系統6、Java ...
  • 後端開發:1、高級java軟體架構師實戰培訓視頻教程2、大型SpringMVC,Mybatis,Redis,Solr,Nginx,SSM分散式電商項目視頻教程3、Spark Streaming實時流處理項目實戰4、Java校招面試 Google面試官親授5、Java開發企業級許可權管理系統6、Java ...
  • 後端開發:1、高級java軟體架構師實戰培訓視頻教程2、大型SpringMVC,Mybatis,Redis,Solr,Nginx,SSM分散式電商項目視頻教程3、Spark Streaming實時流處理項目實戰4、Java校招面試 Google面試官親授5、Java開發企業級許可權管理系統6、Java ...
  • 一.POI結構與常用類 1.POI介紹 Apache POI是Apache軟體基金會的開源項目,POI提供API給Java程式對Microsoft Office格式檔案讀和寫的功能。 .NET的開發人員則可以利用NPOI (POI for .NET) 來存取 Microsoft Office文檔的功 ...
  • 設計模式(Design pattern)是一套被反覆使用的、代碼設計經驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 常見的設計模式有23種。分為三大類:創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。結構型模式,共七種:適配器模式、 ...
  • 問:程式員編寫的第一個程式是啥米? 猿:這個問題,so easy。我選擇閉著眼睛回答,那就是“HelloWorld”。 問:那在python裡面怎麼來進行HelloWord呢? 猿:聽我細細到來。 小黑板開始講課了: 知識點: print():列印。將要列印的內容寫入print()後的括弧中,Hel ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...