使用 MEF 公开 Silverlight“.NET研究” MVVM 应用程序中的接口

简介:   下载代码示例   许多开发人员可能都将 Silverlight 视为以 Web 为中心的技术,但实际上,它已经成为构建任何应用程序的优秀平台。

  下载代码示例

  许多开发人员可能都将 Silverlight 视为以 Web 为中心的技术,但实际上,它已经成为构建任何应用程序的优秀平台。 Silverlight 本身就支持许多概念,例如数据绑定、值转换器、导航、浏览器外操作和 COM 互操作,因此它可以相对直观简便地创建任何种类的应用程序。 我说的是“任何种类”,其中当然也包括企业级应用程序。

  利用 Model-View-ViewModel (MVVM) 模式来创建 Silverlight 应用程序,这使您除了能够使用 Silverlight 中已有的功能以外,还能获得更强的可维护性、可测试性以及用户界面与其背后的逻辑之间的可分离性。 当然,您不需要完全靠自己来解决所有问题。 有很多信息和工具可以帮助您入门。 例如,MVVM Light Toolkit (mvvmlight.codeplex.com) 是一款轻量级框架,用于通过 Silverlight 和 Windows Presentation Foundation (WPF) 来实现 MVVM;借助代码生成,WCF RIA 服务 (silverlight.net/getstarted/riaservices) 可帮助您轻松访问 Windows Communication Foundation (WCF) 服务和数据库。

  利用托管可扩展性框架 (mef.codeplex.com)(简称为 MEF),您可以进一步扩展 Silverlight 应用程序。 此框架提供了探测功能,可利用组件和复合创建可扩展的应用程序。

  在本文的其余部分,我将介绍如何使用 MEF 来集中管理 View 和 ViewModel 创建工作。 当您获得此工具之后,所能做到的就不只是将 ViewModel 放入 View 的 DataContext 中了。 所有这些都将通过自定义内置的 Silverlight 导航来实现。 当用户导航到给定的 URL 时,MEF 会拦截此请求,查看路线(有点类似于 ASP.NET MVC),查找匹配的 View 和 ViewModel,通知 ViewModel 发生了什么,然后显示 View。

  Getting Started with MEF

  由于 MEF 是将本示例中所有部分都连接起来的引擎,因此最好从它开始。 如果您还不熟悉 MEF,请先阅读 Glenn Block 的文章“在 .NET 4 中使用托管可扩展性框架构建可组合的应用程序”,该文章发表在 MSDN 杂志 的 2010 年 2 月号上 (msdn.microsoft.com/magazine/ee291628)。

  首先,您需要处理 App 类的 Startup 事件,以便在应用程序启动时正确配置 MEF:

 
 
private void OnStart( object sender, StartupEventArgs e) {
// Initialize the container using a deployment catalog.
var catalog = new DeploymentCatalog();
var container
= CompositionHost.Initialize(catalog);
// Export the container as singleton.
container.ComposeExportedValue < CompositionContainer > (container);
// Make sure the MainView is imported.
CompositionInitializer.SatisfyImports( this );
}

  部署目录确保了所有程序集都被扫描以便导出,然后用于创建 CompositionContainer。 由于导航稍后还需要此容器来执行某些工作,因此务必将此容器的实例注册为导出的值。 这样,就可以随时根据需要导入同一个容器。

  另一个选择是将容器保存为静态对象,但是这将在类之间创建紧耦合,而这并不是一种好的做法。

  扩展 Silverlight 导航

  Silverlight 导航应用程序是一个 Visual Studio 模板。利用该模板,您可以快速创建应用程序,使用承载了内容的 Frame 来支持导航。 Frame 所带来的最大好处是它可以与浏览器的“后退”和“前进”按钮集成,并且支持深度链接。 请看以下代码:

 
 
< navigation:Frame x:Name = " ContentFrame "
Style
= " {StaticResource ContentFrameStyle} "
Source
= " Customers "
NavigationFailed
= " OnNavigationFailed " >
< i:Interaction.Behaviors >
< fw:CompositionNavigationBehavior />
</ i:Interaction.Behaviors >
</ navigation:Frame >

  这只是一个普通的框架,它从导航到 Customers 开始。 正如您看到的,此 Frame 不包含 UriMapper(您可以在其中将 Customers 链接到一个 XAML 文件,例如 /Views/Customers.aspx)。 它唯一包含的内容是我的自定义行为 CompositionNavigationBehavior。 利用行为(来自 System.Windows.Interactivity 程序集),您可以扩展现有的控件,例如本例中的 Frame。

  我们来看一看这个 CompositionNavigationBehavior 都做些什么。 首先,您可以看到,由于 Import 特性的缘故,该行为需要 CompositionContainer 和 CompositionNavigationLoader(后文将详细介绍)。 随后,构造函数将使用 CompositionInitializer 的 SatisfyImports 方法强制执行 Import。 请注意,仅当您别无选择时,才应该使用此方法,因为它实际上会将您的代码与 MEF 紧密耦合到一起。

  CompositionNavigationBehavior

 
 
public class CompositionNavigationBehavior : Behavior < Frame > {
private bool processed;
[Import]
public CompositionContainer Container {
get ; set ;
}

[Import]
public CompositionNavigationContentLoader Loader {
get ; set ;
}

public CompositionNavigationBehavior() {
if ( ! DesignerProperties.IsInDesignTool)
CompositionInitializer.SatisfyImports(
this );
}

protected override void OnAttached() {
base .OnAttached();
if ( ! processed) {
this .RegisterNavigationService();
this .SetContentLoader();
processed
= true ;
}
}

private void RegisterNavigationService() {
var frame
= AssociatedObject;
var svc
= new NavigationService(frame);
Container.ComposeExportedValue
< INavigationService > (svc);
}

private void SetContentLoader() {
var frame
= AssociatedObject;
frame.ContentLoader
= Loader;
frame.JournalOwnership
= JournalOwnership.Automatic;
}
}

  连接 Frame 时,将创建一个 NavigationService,并用其包装 Frame。 使用 ComposeExportedValue 时,此包装的实例会在容器内注册。

  在创建容器时,此容器的实例也会在其自身内注册。 因此,CompositionContainer 的 Import 总是能为您提供相同的对象;这就是我在 App 类的 Startup 事件中使用 ComposeExportedValue 的原因。 现在,CompositionNavigationBehavior 使用 Import 特性请求 CompositionContainer,并且将在 SatisfyImports 运行后获得它。

  在注册 INavigationService 的实例时,会发生同样的情况。 现在,就可以从应用程序内的任何地方请求 INavigationService(它包装了 Frame)了。 不需要将 ViewModel 耦合到框架,您就能访问以下内容:

 
 
public interface INavigationService {
void Navigate( string path);
void Navigate( string path, params object [] args);
}

  现在,假设您有一个 ViewModel 显示您的所有客户,并且此 ViewModel 应该能够打开某个具体的客户。这可以通过以下代码完成:

 
 
[Import]
public INavigationService NavigationService {
get ; set ;
}
private void OnOpenCustomer() {
NavigationService.Navigate(
" Customer/{0} " , SelectedCustomer.Id);
}

  但是在继续之前,首先要讨论一下 CompositionNavigationBehavior 中的 SetContentLoader 方法。它用于更改 Frame 的 ContentLoader。这是在 Silverlight 中支持可扩展性的一个完美例子。您可以提供自己的 ContentLoader(实现 INavigationContentLoader 接口),从而真正提供一些内容以便在 Frame 中显示。

  现在,您可以看到各个方面如何逐步到位,后面的主题(扩展 MEF)也将变得清晰起来。

  继续扩展 MEF

  这里的目标是:您可以导航到特定路径(从 ViewModel 或您的浏览器地址栏),然后 CompositionNavigationLoader 就会完成其余的工作。 它应该分析 URI,查找匹配的 ViewModel 和匹配的 View,然后将两者组合。

  通常,您需要编写类似以下的代码:

 
 
[Export( typeof (IMainViewModel))]
public class MainViewModel  

  在本例中,将 Export 特性与一些额外配置(称为元数据)结合使用,会相当有趣。 图 2 显示了一个元数据特性示例。

  创建 ViewModelExportAttribute

 
 
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple
= false )]
public class ViewModelExportAttribute :
ExportAttribute, IViewModelMetadata {
public Type ViewModelContract { get ; set ; }
public string NavigationPath { get ; set ; }
public string Key { get ; set ; }

public ViewModelExportAttribute(Type viewModelContract,
string navigationPath) : base ( typeof (IViewModel)) {

this .NavigationPath = navigationPath;
this .ViewModelContract = viewModelContract;
if (NavigationPath != null &&
NavigationPath.Contains(
" / " )) {
// Split the path to get the arguments.
var split = NavigationPath.Split( new char [] { ' / ' },
StringSplitOptions.RemoveEmptyEntries);
// Get the key.
Key = split[ 0 ];
}
else {
// No arguments, use the whole key.
Key = NavigationPath;
}
}
}

  此特性没有任何特殊的地方。 除了 ViewModel 接口以外,它还允许您定义导航路径,例如 Customer/{Id}。 然后,它将使用 Customer 作为 Key,使用 {Id} 作为参数之一,对此路径进行处理。 下面是如何使用此特性的示例:

 
 
[ViewModelExport( typeof (ICustomerDetailViewModel), " Customer/{id} " )]
public class CustomerDetailViewModel : ICustomerDetailViewModel

  在继续之前,有几点重要事项需要注意。 首先,您的特性应该使用 [MetadataAttribute] 进行修饰,才能正常工作。 其次,您的特性应该实现一个接口,其中包含您希望公开为元数据的值。 最后,注意特性的构造函数,它会向基构造函数传递类型。 用此特性修饰的类将使用这种类型公开。 在我的示例中,此类型是 IViewModel。

  它用于导出 ViewModel。 如果您希望在某些地方导入它们,应该编写类似以下的代码:

 
 
[ImportMany( typeof (IViewModel))]
public List < Lazy < IViewModel, IViewModelMetadata >> ViewModels {
get ;
set ;
}

  这将为您提供一个列表,其中包含所有导出的 ViewModels 及其相应的元数据,因此您可以枚举该列表,并从中选出您感兴趣的项(基于元数据)。 事实上,Lazy 对象将确保只有您感兴趣的项才会真正实例化。

  View 将需要类似以下的内容:

 
 
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple
= false )]
public class ViewExportAttribute :
ExportAttribute, IViewMetadata {

public Type ViewModelContract { get ; set ; }
public ViewExportAttribute() : base ( typeof (IView)) {
}
}

  此示例中也没有什么特殊的地方。 利用此特性,您可以设置 View 应该链接到的 ViewModel 的合约。

  以下是 AboutView 的示例:

 
 
[ViewExport(ViewModelContract = typeof (IAboutViewModel))]
public partial class AboutView : Page, IView {
public AboutView() {
InitializeComponent();
}
}

  自定义 INavigationContentLoader

  现在,整体框架已经搭建好,我们来看一看如何控制用户导航时加载的内容。 若要创建自定义的内容加载器,需要实现以下接口:

 
 
public interface INavigationContentLoader {
IAsyncResult BeginLoad(Uri targetUri, Uri currentUri,
AsyncCallback userCallback,
object asyncState);
void CancelLoad(IAsyncResult asyncResult);
bool CanLoad(Uri targetUri, Uri currentUri);
LoadResult EndLoad(IAsyncResult asyncResult);
}

  此接口中最重要的部分是 BeginLoad 方法,因为此方法应该返回一个 AsyncResult,其中包含将要显示在 Frame 中的内容项。 图 3 显示了自定义 INavigationContentLoader 的具体实现。

  自定义 INavigationContentLoader

 
 
[Export] public class CompositionNavigationContentLoader :
INavigationContentLoader {
[ImportMany(
typeof (IView))]
public IEnumerable < ExportFactory < IView, IViewMetadata >>
ViewExports {
get ; set ; }

[ImportMany(
typeof (IViewModel))]
public IEnumerable < ExportFactory < IViewModel, IViewModelMetadata >>
ViewModelExports {
get ; set ; }

public bool CanLoad(Uri targetUri, Uri currentUri) {
return true ;
}

public void CancelLoad(IAsyncResult asyncResult) {
return ;
}

public IAsyncResult BeginLoad(Uri targetUri, Uri currentUri,
AsyncCallback userCallback,
object asyncState) {
// Convert to a dummy relative Uri so we can access the host.
var relativeUri = new Uri( " http:// " + targetUri.OriginalString,
UriKind.Absolute);

// Get the factory for the ViewModel.
var viewModelMapping = ViewModelExports.FirstOrDefault(o =>
o.Metadata.Key.Equals(relativeUri.Host,
StringComparison.OrdinalIgnoreCase));

if (viewModelMapping == null )
throw new InvalidOperationException(
String.Format(
" Unable to navigate to: {0}. "
+
" Could not locate the ViewModel. " ,
targetUri.OriginalString));

// Get the factory for the View.
var viewMapping = ViewExports.FirstOrDefault(o =>
o.Metadata.ViewModelContract
==
viewModelMapping.Metadata.ViewModelContract);

if (viewMapping == null )
throw new InvalidOperationException(
String.Format(
" Unable to navigate to: {0}. "
+
" Could not locate the View. " ,
targetUri.OriginalString));

// Resolve both the View and the ViewModel.
var viewFactory = viewMapping.CreateExport();
var view
= viewFactory.Value as Control;
var viewModelFactory
= viewModelMapping.CreateExport();
var viewModel
= viewModelFactory.Value as IViewModel;

// Attach ViewModel to View.
view.DataContext = viewModel;
viewModel.OnLoaded();

// Get navigation values.
var values = viewModelMapping.Metadata.GetArgumentValues(targetUri);
viewModel.OnNavigated(values);

if (view is Page) {
Page page
= view as Page;
page.Title
= viewModel.GetTitle();
}
else if (view is ChildWindow) {
ChildWindow window
= view as ChildWindow;
window.Title
= viewModel.GetTitle();
}

// Do not navigate if it's a ChildWindow.
if (view is ChildWindow) {
ProcessChildWindow(view
as ChildWindow, viewModel);
return null ;
}
else {
// Navigate because it's a Control.
var result = new CompositionNavigationAsyncResult(asyncState, view);
userCallback(result);
return result;
}
}

private void ProcessChildWindow(ChildWindow window,
IViewModel viewModel) {
// Close the ChildWindow if the ViewModel requests it.
var closableViewModel = viewModel as IClosableViewModel;

if (closableViewModel != null ) {
closableViewModel.CloseView
+= (s, e) => { window.Close(); };
}

// Show the window.
window.Show();
}

public LoadResult EndLoad(IAsyncResult asyncResult) {
return new LoadResult((asyncResult as
CompositionNavigationAsyncResult).Result);
}
}

  正如您看到的,此类中执行了很多操作,但它实际上相当简单。 首先,请注意 Export 特性。 要想在 CompositionNavigationBehavior 中导入此类,此特性是必需的。

  此类中最重要的部分是 ViewExports 和 ViewModelExports 属性。 这些枚举包含 View 和 ViewModel 的所有导出内容,包括其元数据。 我没有使用 Lazy 对象,而是使用了 ExportFactory。 两者的区别非常大! 两个类都只有在必要时才会实例化对象,但区别是:如果使用 Lazy 类,您只能为该对象创建一个实例。 而 ExportFactory 类(按照 Factory 模式命名)允许您随时根据需要,请求为该类型的对象创建一个新实例。

  最后,还要注意 BeginLoad 方法。 奇妙的事情就要发生了。 此方法将向 Frame 提供上海徐汇企业网站制作内容,以便在导航到给定的 URI 之后显示出来。

  创建和处理对象

  假设您让 Frame 导航到 Customers。 这就是您将在 BeginLoad 方法的 targetUri 参数中发现的内容。 一旦您获得了此内容,就可以开始工作了。

  要做的第一件事是找到正确的 ViewModel。 ViewModelExports 属性是一个枚举,它包含所有导出项及其元数据。 使用 lambda 表达式,您可以根据其键值找到正确的 ViewModel。 请记住以下几点:

 
 
[ViewModelExport( typeof (ICustomersViewModel), " Customers " )]
public class CustomersViewModel : ContosoViewModelBase, ICustomersViewModel

  好吧,假设您导航到 Customers。 然后,以下代码将找到正确的 ViewModel:

 
 
var viewModelMapping = ViewModelExports.FirstOrDefault(o => o.Metadata.Key.Equals( " Customers " , StringComparison.OrdinalIgnoreCase));

  一旦定位 ExportFactory 之后,也会为 View 进行同样的操作。 但是,您不需要查找导航键,而是要按照 ViewModelExportAttribute 和 ViewModelAttribute 中的定义查找 ViewModelContract:

 
 
[ViewExport(ViewModelContract = typeof (IAboutViewModel))
public partial class AboutView : Page     

  一旦找到了这两个 ExportFactory,最困难的部分就完成了。 现在,CreateExport 方法允许您为 View 和 ViewModel 创建新实例:

 
 
var viewFactory = viewMapping.CreateExport();
var view
= viewFactory.Value as Control;
var viewModelFactory
= viewModelMapping.CreateExport();
var viewModel
= viewModelFactory.Value as IViewModel;

  在创建 View 和 ViewModel 之后,ViewModel 将存储到 View 的 DataContext 中,从而开始必要的数据绑定。 并调用 ViewModel 的 OnLoaded 方法,通知 ViewModel:所有繁重的工作都已完成,所有 Import(如果存在)都已导入。

  当您使用 Import 和 ImportMany 特性时,不应低估这最后一步的重要性。 在许多情况下,您都希望在创建 ViewModel 时执行某些操作,但只有在所有内容都正确加载时才能这么做。 如果您使用了 ImportingConstructor,您肯定知道何时导入了所有 Import(就是调用该构造函数的时候)。 但是在处理 Import/ImportMany 特性时,您应该开始在所有属性中编写代码来设置标记,以便了解何时导入了所有属性。

  在本例中,OnLoaded 方法为您解决了这个问题。

  向 ViewModel 传递参数

  看一下 IViewModel 接口,并且要注意 OnNavigated 方法:

 
 
public interface IViewModel {
void OnLoaded();
void OnNavigated(NavigationArguments args);
string GetTitle();
}

  例如,当您导航到 Customers/1 时,系统会分析此路径,并在 NavigationArguments 类(这不过是一个具有 GetInt、GetString 等额外方法的 Dictionary)中组合参数。 由于每个 ViewModel 都必须实现 IViewModel 接口,因此可以在解析 ViewModel 之后调用 OnNavigated:

 
 
// Get navigation values.
var values = viewModelMapping.Metadata.GetArgumentValues(targetUri); viewModel.OnNavigated(values);

  当 CustomersViewModel 希望打开 CustomerDetailViewModel 时,将发生以下情况:

 
 
NavigationService.Navigate( " Customer/{0} " , SelectedCustomer.Id);

  然后,这些参数将传送至 CustomerDetailViewModel,并可用于传递给 DataService。例如:

 
 
public override void OnNavigated(NavigationArguments args) {
var id
= args.GetInt( " Id " );
if (id.HasValue) {
Customer
= DataService.GetCustomerById(id.Value);
}
}

  为了查找参数,我编写了一个类,其中包含两个扩展方法,用于根据 ViewModel 元数据中的信息执行某些操作。 这再次证明 MEF 中的元数据概念真的非常有用。

导航参数的扩展方法

  最后的工作

  如果 View 是 Page 或 ChildWindow,则此控件的标题也应该从 IViewModel 对象中提取出来。 这样,您就可以根据当前客户动态设置 Page 和 ChildWindow 的标题。

设置客户窗口标题

  在完成所有这些细微的工作之后,还有最后一步。 如果 View 是 ChildWindow,则应该显示窗口。 但如果 ViewModel 实现 IClosableViewModel,此 ViewModel 的 CloseView 事件则应该链接到 ChildWindow 的 Close 方法。

  IClosableViewModel 接口非常简单:

 
 
public interface IClosableViewModel : IViewModel {
event EventHandler CloseView;
}

  对 ChildWindow 的处理也非常简单。 当 ViewModel 引发 CloseView 事件时,就会调用 ChildWindow 的 Close 方法。 因此,您可以间接将 ViewModel 连接到 View:

 
 
// Close the ChildWindow if the ViewModel requests it.
var closableViewModel = viewModel as IClosableViewModel;
if (closableViewModel != null ) {
closableViewModel.CloseView
+= (s, e) => {
window.Close();
};
}

// Show the window.
window.Show();

  如果 View 不是 ChildWindow,则应该直接在 IAsyncResult 中提供它。 这将在 Frame 中显示 View。

  好了。 现在,您已经看到了构造 View 和 ViewModel 的整个过程。

  使用示例代码

  本文的代码下载包含一个 MVVM 应用程序,该应用程序利用 MEF 实现了这种自定义导航。 该解决方案包含以下示例:

  • 导航到普通的 UserControl
  • 通过传递参数 (.../#Employee/DiMattia) 导航到普通的 UserControl
  • 通过传递参数 (.../#Customer/1) 导航到普通的 ChildWindow
  • INavigationService、IDataService 等的 Import
  • ViewExport 和 ViewModelExport 配置的示例

  本文应该已经为如何让示例运转起来提供了一个不错的思路。 为了加深理解,请研究该代码,并对其进行自定义,以便创建您自己的应用程序。 您将会看到 MEF 有多么强大和灵活。

目录
相关文章
|
4月前
|
存储 Shell Linux
快速上手基于 BaGet 的脚本自动化构建 .net 应用打包
本文介绍了如何使用脚本自动化构建 `.net` 应用的 `nuget` 包并推送到指定服务仓库。首先概述了 `BaGet`——一个开源、轻量级且高性能的 `NuGet` 服务器,支持多种存储后端及配置选项。接着详细描述了 `BaGet` 的安装、配置及使用方法,并提供了 `PowerShell` 和 `Bash` 脚本实例,用于自动化推送 `.nupkg` 文件。最后总结了 `BaGet` 的优势及其在实际部署中的便捷性。
187 10
|
5月前
|
Linux C++ Windows
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
|
2月前
|
开发框架 监控 .NET
【Azure App Service】部署在App Service上的.NET应用内存消耗不能超过2GB的情况分析
x64 dotnet runtime is not installed on the app service by default. Since we had the app service running in x64, it was proxying the request to a 32 bit dotnet process which was throwing an OutOfMemoryException with requests >100MB. It worked on the IaaS servers because we had the x64 runtime install
|
2月前
|
JSON 算法 安全
JWT Bearer 认证在 .NET Core 中的应用
【10月更文挑战第30天】JWT(JSON Web Token)是一种开放标准,用于在各方之间安全传输信息。它由头部、载荷和签名三部分组成,用于在用户和服务器之间传递声明。JWT Bearer 认证是一种基于令牌的认证方式,客户端在请求头中包含 JWT 令牌,服务器验证令牌的有效性后授权用户访问资源。在 .NET Core 中,通过安装 `Microsoft.AspNetCore.Authentication.JwtBearer` 包并配置认证服务,可以实现 JWT Bearer 认证。具体步骤包括安装 NuGet 包、配置认证服务、启用认证中间件、生成 JWT 令牌以及在控制器中使用认证信息
137 2
|
4月前
|
数据采集 JSON API
.NET 3.5 中 HttpWebRequest 的核心用法及应用
【9月更文挑战第7天】在.NET 3.5环境下,HttpWebRequest 类是处理HTTP请求的一个核心组件,它封装了HTTP协议的细节,使得开发者可以方便地发送HTTP请求并接收响应。本文将详细介绍HttpWebRequest的核心用法及其实战应用。
183 6
|
5月前
|
Linux iOS开发 开发者
跨平台开发不再难:.NET Core如何让你的应用在Windows、Linux、macOS上自如游走?
【8月更文挑战第28天】本文提供了一份详尽的.NET跨平台开发指南,涵盖.NET Core简介、环境配置、项目结构、代码编写、依赖管理、构建与测试、部署及容器化等多个方面,帮助开发者掌握关键技术与最佳实践,充分利用.NET Core实现高效、便捷的跨平台应用开发与部署。
500 3
|
5月前
|
缓存 Java API
【揭秘】.NET高手不愿透露的秘密:如何让应用瞬间提速?
【8月更文挑战第28天】本文通过对比的方式,介绍了针对 .NET 应用性能瓶颈的优化方法。以一个存在响应延迟和并发处理不足的 Web API 项目为例,从性能分析入手,探讨了使用结构体减少内存分配、异步编程提高吞吐量、EF Core 惰性加载减少数据库访问以及垃圾回收机制优化等多个方面,帮助开发者全面提升 .NET 应用的性能和稳定性。通过具体示例,展示了如何在不同场景下选择最佳实践,以实现更高效的应用体验。
70 3
|
5月前
|
前端开发 JavaScript 开发工具
跨域联姻:React.NET——.NET应用与React的完美融合,解锁前后端高效协作新姿势。
【8月更文挑战第28天】探索React.NET,这是将热门前端框架React与强大的.NET后端无缝集成的创新方案。React以其组件化和虚拟DOM技术著称,能构建高性能、可维护的用户界面;.NET则擅长企业级应用开发。React.NET作为桥梁,使.NET应用轻松采用React构建前端,并优化开发流程与性能。通过直接托管React组件,.NET应用简化了部署流程,同时支持服务器端渲染(SSR),提升首屏加载速度与SEO优化。
125 1
|
5月前
|
存储 缓存 安全
.NET 在金融行业的应用:高并发交易系统的构建与优化之路
【8月更文挑战第28天】在金融行业,交易系统需具备高并发处理、低延迟及高稳定性和安全性。利用.NET构建此类系统时,可采用异步编程提升并发能力,优化数据库访问以降低延迟,使用缓存减少数据库访问频率,借助分布式事务确保数据一致性,并加强安全性措施。通过综合优化,满足金融行业的严苛要求。
69 1
|
5月前
|
大数据 开发工具 开发者
从零到英雄:.NET核心技术带你踏上编程之旅,构建首个应用,开启你的数字世界探险!
【8月更文挑战第28天】本文带领读者从零开始,使用强大的.NET平台搭建首个控制台应用。无论你是新手还是希望扩展技能的开发者,都能通过本文逐步掌握.NET的核心技术。从环境搭建到创建项目,再到编写和运行代码,详细步骤助你轻松上手。通过计算两数之和的小项目,你不仅能快速入门,还能为未来开发更复杂的应用奠定基础。希望本文为你的.NET学习之旅开启新篇章!
48 1