ASP.NET Core应用的错误处理[4]:StatusCodePagesMiddleware中间件如何针对响应码呈现错误页面

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介:

StatusCodePagesMiddleware中间件与ExceptionHandlerMiddleware中间件比较类似,它们都是在后续请求处理过程中“出错”的情况下利用一个错误处理器来完成最终的请求处理与响应的任务。它们之间的差异在于对“错误”的界定上,对于ExceptionHandlerMiddleware中间件来说,它所谓的错误就是抛出异常,但是对于StatusCodePagesMiddleware中间件来说,则将介于400~599之间的响应状态码视为错误。如下面的代码片段所示,StatusCodePagesMiddleware中间件也采用“标准”的定义方式,针对它的配置选项通过一个对应的对象以Options模式的形式提供给它。 [本文已经同步到《ASP.NET Core框架揭秘》之中]

   1: public class StatusCodePagesMiddleware
   2: {
   3:     public StatusCodePagesMiddleware(RequestDelegate next, IOptions<StatusCodePagesOptions> options);
   4:     public Task Invoke(HttpContext context);
   5: }

除了针对错误的界定,StatusCodePagesMiddleware和ExceptionHandlerMiddleware这两个中间件对于错误处理器的表达也不相同。我们知道ExceptionHandlerMiddleware中间件使用的错误处理器实际上就是一个类型为RequestDelegate的委托对象,但是错误处理器之于StatusCodePagesMiddleware中间件来说则是一个类型为Func<StatusCodeContext, Task>的委托对象。如下面的代码片段所示,为StatusCodePagesMiddleware中间件提供配置选项的StatusCodePagesOptions对象的唯一目的就是提供这个作为错误处理器的委托对象。

   1: public class StatusCodePagesOptions
   2: {
   3:     public Func<StatusCodeContext, Task> HandleAsync { get; set; }
   4: }

我们知道一个RequestDelegate对象相当于一个类型为Func<HttpContext, Task>类型的委托对象,而一个StatusCodeContext对象实际上也是对一个HttpContext对象的封装,所以StatusCodePagesMiddleware中间件和ExceptionHandlerMiddleware中间件所使采用的错误处理器并没有本质上的不同。如下面的代码片段所示,除了从StatusCodeContext对象中获取代表当前请求上下文的HttpContext对象之外,我们还可以通过其Next属性得到一个RequestDelegate对象,它代表由后续中间件组成的请求处理管道。至于另一个属性Options,很明显它返回我们在创建StatusCodePagesMiddleware中间件所指定的StatusCodePagesOptions对象。

   1: public class StatusCodeContext
   2: {    
   3:     public HttpContext             HttpContext { get; }
   4:     public RequestDelegate         Next { get; }
   5:     public StatusCodePagesOptions  Options { get; }
   6:  
   7:     public StatusCodeContext(HttpContext context, StatusCodePagesOptions options, RequestDelegate next);
   8: }

一、针对响应状态码的错误处理

由于采用了针对响应状态码的错误处理策略,所以实现在StatusCodePagesMiddleware中间件中的所有错误处理操作只会发生在当前响应状态码在400~599之间的情况,如下所示的代码片段体现了这一点。从下面给出的代码片段可以看出,StatusCodePagesMiddleware中间件在决定是否执行错误处理操作时除了会查看当前响应状态码之外,还会查看响应内容以及媒体类型,如果已经包含了响应内容或者设置了媒体类型,该中间件将不会执行任何操作。

   1: public class StatusCodePagesMiddleware
   2: {
   3:     private  RequestDelegate            _next;
   4:     private  StatusCodePagesOptions     _options;
   5:  
   6: public StatusCodePagesMiddleware(RequestDelegate next, 
   7:     IOptions<StatusCodePagesOptions> options)
   8:     {
   9:         _next         = next;
  10:         _options      = options.Value;
  11:     }
  12:  
  13:     public async Task Invoke(HttpContext context)
  14:     {          
  15:         await _next(context);
  16:         var response = context.Response;
  17:         if ((response.StatusCode >= 400 && response.StatusCode <= 599) &&!response.ContentLength.HasValue && string.IsNullOrEmpty(response.ContentType))
  18:         {
  19:             await _options.HandleAsync(new StatusCodeContext(context, _options, _next));
  20:         }
  21:     }
  22: }

StatusCodePagesMiddleware中间件针对错误的处理非常简单,它只需要从StatusCodePagesOptions对象中提取出作为错误处理器的这个Func<StatusCodeContext, Task>对象,然后创建一个StatusCodeContext对象作为输入参数调用这个委托对象即可。

二、阻止异常处理

如果当前响应已经被写入了内容,或者响应的媒体类型已经被预先设置,那么StatusCodePagesMiddleware中间件将不会再执行任何的错误处理操作。这种情况实际上代表由后续中间件构成的管道可能需要自行控制当前的响应,所以StatusCodePagesMiddleware中间件不应该再做任何的干预。从这个意义上来讲,StatusCodePagesMiddleware中间件仅仅是作为一种后备的错误处理机制而已。

更进一步来将,如果后续的某个中间件返回了一个状态码在400~599之间的响应,并且这个响应只有报头集合没有主体(媒体类型自然也不会设置),那么按照我们在上面给出的错误处理逻辑,StatusCodePagesMiddleware中间件还是会按照自己的策略来处理并响应请求。为了解决这种情况下,我们必须赋予后续中间件一个能够阻止StatusCodePagesMiddleware中间件进行错误处理的能力。

阻止StatusCodePagesMiddleware中间件进行错误处理的机制是借助于一个名为StatusCodePagesFeature的特性来实现的。StatusCodePagesFeature对应如下这个IStatusCodePagesFeature接口,它具有唯一的布尔类型的属性成员Enabled。默认使用的StatusCodePagesFeature类型实现了这个接口,默认情况下这个开关是开启的。

   1: public interface IStatusCodePagesFeature
   2: {
   3:     bool Enabled { get; set; }
   4: }
   5:  
   6: public class StatusCodePagesFeature : IStatusCodePagesFeature
   7: {
   8:     public bool Enabled { get; set; } = true ;
   9: }

StatusCodePagesMiddleware中间件在将请求交付给后续管道之前,它会创建一个StatusCodePagesFeature特性对象并将其添加到当前HttpContext之中。当最终决定是否执行错误处理操作的时候,它还会通过这个特性检验是否某个后续的中间件不希望自己“画蛇添足”地进行不必要的错误处理,如下的代码片段很好的体现了这一点。

   1: public class StatusCodePagesMiddleware
   2: {
   3:
   4:     public async Task Invoke(HttpContext context)
   5:     {
   6:         StatusCodePagesFeature feature = new StatusCodePagesFeature();
   7:         context.Features.Set<IStatusCodePagesFeature>(feature);
   8:  
   9:         await _next(context);
  10:         var response = context.Response;
  11:         if ((response.StatusCode >= 400 && response.StatusCode <= 599) && !response.ContentLength.HasValue &&string.IsNullOrEmpty(response.ContentType) &&
  12:             )
  13:         {
  14:             await _options.HandleAsync(new StatusCodeContext(context, _options, _next));
  15:         }
  16:     }
  17: }

我们通过一个简单的实例来演示如果利用这个StatusCodePagesFeature特性来屏蔽StatusCodePagesMiddleware中间件。在下面这个应用中,我们将针对请求的处理定义在Invoke方法中,该方法会返回一个状态码为“401 Unauthorized”的响应。我们通过随机数让这个方法会在50%的情况下利用StatusCodePagesFeature特性来阻止StatusCodePagesMiddleware中间件自身对错误的处理。我们通过调用扩展方法UseStatusCodePages注册的StatusCodePagesMiddleware中间件会直接响应一个内容为“Error occurred!”的字符串。

   1: public class Program
   2: {
   3:     public static void Main()
   4:     {
   5:         new WebHostBuilder()
   6:             .UseKestrel()
   7:             .Configure(app => app
   8:                 .UseStatusCodePages(async context => await context.HttpContext.Response.WriteAsync("Error occurred!"))
   9:                 .Run(Invoke))
  10:             .Build()
  11:             .Run();
  12:     }
  13:  
  14:     private static Random _random = new Random();
  15:     private static Task Invoke(HttpContext context)
  16:     {
  17:         context.Response.StatusCode = 401;
  18:  
  19:         if (_random.Next() % 2 == 0)
  20:         {
  21:             context.Features.Get<IStatusCodePagesFeature>().Enabled = false;
  22:         }
  23:         return Task.CompletedTask;
  24:     }
  25: }

对于针对该应用的请求来说,我们会得到如下两种不同的响应。没有主体内容响应是通过Invoke方法产生的,这种情况下发生在StatusCodePagesMiddleware中间件通过StatusCodePagesFeature特性被屏蔽的时候。具有主体内容的响应则来源于StatusCodePagesMiddleware中间件。

   1: HTTP/1.1 401 Unauthorized
   2: Date: Sun, 18 Dec 2016 01:59:37 GMT
   3: Server: Kestrel
   4: Content-Length: 15
   5:  
   6: Error occurred!
   7:  
   8:  
   9: HTTP/1.1 401 Unauthorized
  10: Date: Sun, 18 Dec 2016 01:59:38 GMT
  11: Content-Length: 0
  12: Server: Kestrel

三、注册StatusCodePagesMiddleware中间件

我们在大部分情况下都会调用ApplicationBuilder相应的扩展方法来注册StatusCodePagesMiddleware中间件。对于StatusCodePagesMiddleware中间件的注册来说,除了我们已经很熟悉的UseStatusCodePages方之外,还具有额外一些扩展方法供我们选择。

UseStatusCodePages

我们可以调用如下三个UseStatusCodePages方法重载来注册StatusCodePagesMiddleware中间件。不论我们调用那个重载,系统最终都会根据提供的StatusCodePagesOptions对象调用构造函数来创建这个中间件对象,而且这个StatusCodePagesOptions必须具有一个作为错误处理器的Func<StatusCodeContext, Task>对象。如果没有指定任何参数,StatusCodePagesOptions对象需要以Options模式的形式注册为服务。

   1: public static class StatusCodePagesExtensions
   2: {   
   3:     public static IApplicationBuilder UseStatusCodePages(this IApplicationBuilder app)
   4:     {      
   5:         return app.UseMiddleware<StatusCodePagesMiddleware>();
   6:     }
   7:  
   8:     public static IApplicationBuilder UseStatusCodePages(this IApplicationBuilder app, StatusCodePagesOptions options)
   9:     {
  10:         return app.UseMiddleware<StatusCodePagesMiddleware>(Options.Create(options));
  11:     }  
  12:     
  13:     public static IApplicationBuilder UseStatusCodePages(this IApplicationBuilder app, Func<StatusCodeContext, Task> handler)
  14:     {       
  15:         return app.UseStatusCodePages(new StatusCodePagesOptions
  16:         {
  17:             HandleAsync = handler
  18:         });
  19:     }
  20: }

由于StatusCodePagesMiddleware中间件最终的目的还是将定制的错误信息响应给客户端,所以我们可以在注册该中间件的时候直接指定响应的内容和媒体类型,这样的注册方式可以通过调用如下这个UseStatusCodePages方法来完成。从如下所示的代码片段我们不难看出,我们通过bodyFormat方法指定的实际上是一个模板,它可以包含一个表示响应状态的占位符(“{0}”)。

   1: public static class StatusCodePagesExtensions
   2: {   
   3:     public static IApplicationBuilder UseStatusCodePages(this IApplicationBuilder app, string contentType, string bodyFormat)
   4:     {
   5:         return app.UseStatusCodePages(context =>
   6:         {
   7:             var body = string.Format(CultureInfo.InvariantCulture, bodyFormat, context.HttpContext.Response.StatusCode);
   8:             context.HttpContext.Response.ContentType = contentType;
   9:             return context.HttpContext.Response.WriteAsync(body);
  10:         });
  11:     }
  12: }

UseStatusCodePagesWithRedirects

如果我们调用UseStatusCodePagesWithRedirects方法,可以让注册的StatusCodePagesMiddleware中间件向指定的路径发送一个客户端重定向。从如下所示的实现代码可以看出,这个作为参数locationFormat的重定向地址也是一个模板,它可以包含一个表示响应状态的占位符(“{0}”)。我们可以指定一个完整的地址,也可以指定一个相对于PathBase的相对路径,后者需要包含表示基地址的“~/”前缀。

   1: public static class StatusCodePagesExtensions
   2: {       
   3:     public static IApplicationBuilder UseStatusCodePagesWithRedirects(this IApplicationBuilder app, string locationFormat)
   4:     {
   5:         if (locationFormat.StartsWith("~"))
   6:         {
   7:             locationFormat = locationFormat.Substring(1);
   8:             return app.UseStatusCodePages(context =>
   9:             {
  10:                 var location = string.Format(CultureInfo.InvariantCulture, locationFormat, context.HttpContext.Response.StatusCode);
  11:                 context.HttpContext.Response.Redirect(context.HttpContext.Request.PathBase + location);
  12:                 return Task.CompletedTask;
  13:             });
  14:         }
  15:         else
  16:         {
  17:             return app.UseStatusCodePages(context =>
  18:             {
  19:                 var location = string.Format(CultureInfo.InvariantCulture, locationFormat, context.HttpContext.Response.StatusCode);
  20:                 context.HttpContext.Response.Redirect(location);
  21:                 return Task.CompletedTask;
  22:             });
  23:         }
  24:     }
  25: }

我们通过一个简单的应用来演示针对客户端重定向的错误页面呈现方式。我们在如下这个应用中注册了一个路由模板为“error/{statuscode}”的路由,路由参数“statuscode”自然代表响应的状态码。在作为路由处理器的HandleError方法中,我们会直接响应一个包含响应状态码的字符串。我们调用UseStatusCodePagesWithRedirects方法注册StatusCodePagesMiddleware中间件的时候将重定义路径设置为“error/{0}”。

   1: public class Program
   2: {
   3:     private static Random _random = new Random();
   4:     public static void Main()
   5:     {
   6:         new WebHostBuilder()
   7:             .UseKestrel()
   8:             .ConfigureServices(svcs => svcs.AddRouting())
   9:             .Configure(app => app
  10:                 .UseStatusCodePagesWithRedirects("~/error/{0}")
  11:                 .UseRouter(builder=>builder.MapRoute("error/{statuscode}", HandleError))
  12:                 .Run(context=>Task.Run(()=>context.Response.StatusCode = _random.Next(400,599))))
  13:             .Build()
  14:             .Run();
  15:     }
  16:         
  17:     private async static Task HandleError(HttpContext context)
  18:     {
  19:         var statusCode = context.GetRouteData().Values["statuscode"];
  20:         await context.Response.WriteAsync($"Error occurred ({statusCode})");
  21:     }
  22: }

针对该应用的请求总是会得到一个状态码在400~599之间的响应, StatusCodePagesMiddleware在此情况下会向我们指定的路径(“~/error/{statuscode}”)发送一个客户端重定向。由于重定向请求的路径与注册的路由相匹配,所以作为路由处理器的HandleError方法会响应如图11所示的这个错误页面。

11

UseStatusCodePagesWithReExecute

除了采用客户端重定向的方式来呈现错误页面之外,我们还可以调用UseStatusCodePagesWithReExecute方法注册StatusCodePagesMiddleware中间件并让它采用服务端重定向的方式来处理错误请求。如下面的代码片段所示,当我们调用这个方法的时候不仅可以指定重定向的路径,还可以指定指定查询字符串。这里作为重定向地址的参数pathFormat依旧是一个路径模板,它可以包含一个表示响应状态的占位符(“{0}”)。

   1: public static class StatusCodePagesExtensions
   2: {
   3:     public static IApplicationBuilder UseStatusCodePagesWithReExecute(this IApplicationBuilder app, string pathFormat, string queryFormat = null);
   4: }

现在我们对上面演示的这个实例略作修改来演示采服务端重定向呈现出来的错误页面。如下面的代码片段所示,我们仅仅将针对UseStatusCodePagesWithRedirects方法的调用替换成针对UseStatusCodePagesWithReExecute方法的调用而已。

   1: public class Program
   2: {
   3:     private static Random _random = new Random();
   4:     public static void Main()
   5:     {
   6:         new WebHostBuilder()
   7:             .UseKestrel()
   8:             .ConfigureServices(svcs => svcs.AddRouting())
   9:             .Configure(app => app
  10:                 .UseStatusCodePagesWithReExecute("/error/{0}")
  11:                 .UseRouter(builder=>builder.MapRoute("error/{statuscode}", HandleError))
  12:                 .Run(context=>Task.Run(()=>context.Response.StatusCode = _random.Next(400,599))))
  13:             .Build()
  14:             .Run();
  15:     }
  16:         
  17:     private async static Task HandleError(HttpContext context)
  18:     {
  19:         var statusCode = context.GetRouteData().Values["statuscode"];
  20:         await context.Response.WriteAsync($"Error occurred ({statusCode})");
  21:     }
  22: }

对于前面演示的实例,由于错误页面是通过客户端重定向的方式呈现出来的,所以浏览器地址栏显示的是重定向地址。我们在选择这个实例中采用了服务端重定向,虽然显示的页面内容并没有不同,但是地址栏上的地址是不会发生改变的

12

之所以被命名为UseStatusCodePagesWithReExecute,是因为通过这方法注册的StatusCodePagesMiddleware中间件进行错误处理的时候,它仅仅是提供的重定向路径和查询字符串应用到当前HttpContext,然后递交给后续管道重新执行。UseStatusCodePagesWithReExecute方法中注册StatusCodePagesMiddleware中间件的实现总体上可以由如下所示的代码片段来体现。

   1: public static class StatusCodePagesExtensions
   2: {    
   3:     public static IApplicationBuilder UseStatusCodePagesWithReExecute(this IApplicationBuilder app,string pathFormat,string queryFormat = null)
   4:     {
   5:         return app.UseStatusCodePages(async context =>
   6:         {
   7:             var newPath = new PathString(string.Format(CultureInfo.InvariantCulture, pathFormat, context.HttpContext.Response.StatusCode));
   8:             var formatedQueryString = queryFormat == null ? null :string.Format(CultureInfo.InvariantCulture, queryFormat, context.HttpContext.Response.StatusCode);            
   9:             context.HttpContext.Request.Path = newPath;
  10:             context.HttpContext.Request.QueryString = newQueryString;
  11:             await context.Next(context.HttpContext);
  12:         });
  13:     }
  14: }

与ExceptionHandlerMiddleware中间价类似,StatusCodePagesMiddleware中间件在处理请求的过程中会改变当前请求上下文的状态,具体体现在将指定的请求路径和查询字符串重新应用到当前请求上下文中。为了不影响前置中间件对请求的正常处理,StatusCodePagesMiddleware中间件在完成自身处理流程之后必须将当前请求上下文恢复到原始的状态。StatusCodePagesMiddleware中间件依旧是采用一个特性来保存原始的路径和查询字符串。这个特性对应的接口为具有如下定义的IStatusCodeReExecuteFeature,令人费解的是该接口仅仅包含两个针对路径的属性,并没有我们希望的用于携带原始查询上下文的属性,但是默认实现类型StatusCodeReExecuteFeature包含了这个属性。

   1: public interface IStatusCodeReExecuteFeature
   2: {
   3:     string OriginalPath { get; set; }
   4:     string OriginalPathBase { get; set; }
   5: }
   6:  
   7: public class StatusCodeReExecuteFeature : IStatusCodeReExecuteFeature
   8: {
   9:     public string OriginalPath { get; set; }
  10:     public string OriginalPathBase { get; set; }
  11:     public string OriginalQueryString { get; set; }
  12: }

当StatusCodePagesMiddleware中间件在处理异常请求的过程中,在将指定的重定向路径和查询字符串应用到当前请求上下文上之前,它会根据原始的上下文创建一个StatusCodeReExecuteFeature特性对象并将其添加到当前HttpContext之上。当整个请求处理过程结束之后,StatusCodePagesMiddleware中间件还会负责将这个特性从当前HttpContext中移除,并恢复原始的请求路径和查询字符串。如下所示的代码片段体现了UseStatusCodePagesWithReExecute方法的真实逻辑。

   1: public static class StatusCodePagesExtensions
   2: {
   3:     public static IApplicationBuilder UseStatusCodePagesWithReExecute(this IApplicationBuilder app,string pathFormat,string queryFormat = null)
   4:     {    
   5:         return app.UseStatusCodePages(async context =>
   6:         {
   7:             var newPath = new PathString(string.Format(CultureInfo.InvariantCulture, pathFormat, context.HttpContext.Response.StatusCode));
   8:             var formatedQueryString = queryFormat == null ? null :string.Format(CultureInfo.InvariantCulture, queryFormat, context.HttpContext.Response.StatusCode);
   9:             var newQueryString = queryFormat == null ? QueryString.Empty : new QueryString(formatedQueryString);
  10:  
  11:             var originalPath = context.HttpContext.Request.Path;
  12:             var originalQueryString = context.HttpContext.Request.QueryString;
  13:  
  14:             context.HttpContext.Features.Set<IStatusCodeReExecuteFeature>(new StatusCodeReExecuteFeature()
  15:             {
  16:                 OriginalPathBase = context.HttpContext.Request.PathBase.Value,
  17:                 OriginalPath = originalPath.Value,
  18:                 OriginalQueryString = originalQueryString.HasValue ? originalQueryString.Value : null,
  19:             });
  20:  
  21:             context.HttpContext.Request.Path = newPath;
  22:             context.HttpContext.Request.QueryString = newQueryString;
  23:             try
  24:             {
  25:                 await context.Next(context.HttpContext);
  26:             }
  27:             finally
  28:             {
  29:                 context.HttpContext.Request.QueryString = originalQueryString;
  30:                 context.HttpContext.Request.Path = originalPath;
  31:                 context.HttpContext.Features.Set<IStatusCodeReExecuteFeature>(null);
  32:             }
  33:         });
  34:     }
  35: }

ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式
ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件
ASP.NET Core应用的错误处理[3]:ExceptionHandlerMiddleware中间件
ASP.NET Core应用的错误处理[4]:StatusCodePagesMiddleware中间件


作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
10天前
|
算法 Java 调度
|
10天前
|
开发框架 缓存 前端开发
利用Visual Basic构建高效的ASP.NET Web应用
【4月更文挑战第27天】本文探讨使用Visual Basic与ASP.NET创建高效Web应用的策略,包括了解两者基础、项目规划、MVC架构、数据访问与缓存、代码优化、异步编程、安全性、测试及部署维护。通过这些步骤,开发者能构建出快速、可靠且安全的Web应用,适应不断进步的技术环境。
|
10天前
|
C# Windows
一款.NET开源、简洁易用的Windows桌面小说阅读应用
一款.NET开源、简洁易用的Windows桌面小说阅读应用
|
10天前
|
开发框架 物联网 测试技术
【专栏】.NET 开发:打造领先应用的基石
【4月更文挑战第29天】本文探讨了.NET开发框架为何成为构建领先应用的首选。高性能与稳定性是.NET的核心优势,它采用先进的技术和优化策略,如.NET Core的轻量级设计和JIT/AOT编译模式。跨平台兼容性让开发者能用相同代码库在不同操作系统上构建应用。现代化的开发体验,如C#语言的创新特性和Visual Studio的强大工具,提升了开发者生产力。丰富的生态系统和广泛支持,包括庞大的开发者社区和微软的持续投入,为.NET提供了坚实后盾。
|
10天前
|
机器学习/深度学习 人工智能 Cloud Native
【专栏】洞察.NET 技术的前沿应用
【4月更文挑战第29天】本文探讨了.NET技术的前沿应用,包括.NET Core的跨平台崛起、云原生及AI/机器学习领域的整合。.NET Core支持多平台运行,开源社区的参与促进了其快速发展和性能优化。Xamarin与.NET MAUI助力跨平台移动应用和统一界面开发,而云原生应用借助.NET Core与Azure云服务得以轻松构建和部署。此外,ML.NET和TensorFlow.NET为.NET开发者提供了机器学习和深度学习工具,推动智能应用和边缘计算的创新。.NET技术正持续演进,引领软件开发新趋势。
|
10天前
|
人工智能 物联网 开发者
【专栏】探究.NET 技术的创新应用
【4月更文挑战第29天】本文探讨了.NET技术的最新进展和创新应用,包括.NET 5及后续版本的统一平台、性能提升、跨平台支持、云集成优化和开源社区的贡献。在创新应用场景中,重点介绍了微服务架构、物联网、AI、游戏开发和移动应用。未来,.NET将持续优化性能,深化云原生应用,集成新兴技术,扩大社区生态,并促进相关教育和培训。开发者应把握.NET技术的潜力,积极参与其发展,创造更多创新软件产品。
|
10天前
|
安全 Linux API
【专栏】.NET 开发:打造卓越应用的秘诀
【4月更文挑战第29天】本文介绍了.NET技术的起源、核心特性和应用场景,揭示了其打造卓越应用的秘诀。自2002年推出,.NET历经发展,现支持跨平台,包括.NET Core和.NET 5。其核心特性包括:跨平台兼容性、面向对象编程、内置安全性和高效性能。丰富的类库、强大的开发工具、简洁的语言语法以及活跃的社区支持,使.NET成为构建高效、安全应用的理想选择。随着技术进步,.NET将持续赋能开发者创造更多可能性。
|
10天前
|
人工智能 安全 API
【专栏】理解 .NET 技术,打造优质应用
【4月更文挑战第29天】本文探讨了如何利用.NET技术构建高质量应用程序,介绍了.NET从2002年发展至今的历程,强调其跨平台能力、高效开发、丰富的类库和API、开源生态及安全性等优势。随着.NET 6的规划,平台将更加统一和跨平台,适应云计算、AI等新兴技术。.NET凭借其特性,成为开发者和企业创新的有力工具,未来将继续扮演重要角色。
|
10天前
|
机器学习/深度学习 自然语言处理 安全
【专栏】.NET 开发:构建智能应用的关键
【4月更文挑战第29天】本文探讨了.NET开发在构建智能应用中的关键作用,强调了其强大的框架、工具集、高效性能和跨平台支持。通过实例展示了.NET在人工智能、物联网及企业级应用中的应用。同时,指出了.NET开发面临的挑战,如技术更新的学习成本、性能优化、资源管理和安全隐私保护,并提出了应对策略。随着技术进步,.NET将在智能应用领域发挥更大作用,推动创新与便利。
|
10天前
|
开发框架 前端开发 JavaScript
采用C#.Net +JavaScript 开发的云LIS系统源码 二级医院应用案例有演示
技术架构:Asp.NET CORE 3.1 MVC + SQLserver + Redis等 开发语言:C# 6.0、JavaScript 前端框架:JQuery、EasyUI、Bootstrap 后端框架:MVC、SQLSugar等 数 据 库:SQLserver 2012
26 0

热门文章

最新文章