艾伟:Microsoft .NET RIA Services快速上手

在MIX 09上,Nikhil Kothari发布了微软的一神作——Microsoft .NET RIA Services。虽然目前的版本仅仅是可怜的"March '09 Preview”,但它已经足够让人兴奋不已。简单地说,在这之前,如果你用到了现在的RIA技术比如Silverlight,你只能选择写大量的服务或者WCF来实现数据的操作功能;而有了.NET RIA Services,你在RIA项目上操作数据,就像ASP.NET那样方便!

Nikhil Kothari在MIX09上介绍.NET RIA Services的视频:

http://www.nikhilk.net/RIA-Services-MIX09.aspx

 

Microsoft .NET RIA Services March '09 Preview及文档下载地址:

http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=76bb3a07-3846-4564-b0c3-27972bcaabce

 

MSDN Code Gallery中的.NET RIA Services Samples

http://code.msdn.microsoft.com/RiaServices

好了,以上是概要,下面让我们说得更详细些。

 

传统的RIA是怎样操作数据的

在去年这个时候,Silverlight 2Beta刚发布,有个朋友问我能不能使用Silverlight直接操作数据库。当时的答案当然是:很遗憾,不行。我们不得不使用大量的Web Services或者WCF来提供对数据库操作的每一个环节,Silverlight只能与数据层“间接接触”。

上图表明了整个过程。这样的数据操作虽然已经被大家习惯,但它是不合理的。就像是在实现“三通”以前,咱们去台湾只能先去香港转机。

博客园的大牛Shareach前几天写了一个Silverlight的聊天程序,数据操作使用的是WCF Duplex Service实现双向通讯,非常牛,大家可以去看看。(围观连接:http://www.cnblogs.com/yinpengxiang/archive/2009/03/23/slChat.html)这是Silverlight操作数据层的一个成功案例,但也会让人觉得悲哀:这样一个表面上很简单的聊天程序,为什么有了WCF的参与就变得很复杂?

这是因为,这样的“间接接触”,不仅不直观,还浪费了开发者大量的经理去考虑一些不该考虑的问题。开发者需要在客户端、Web Service端,BLL端各写一个不同版本的数据操作代码,并且还要考虑他们之间交互的安全性、网络情况等等,简直就是一个浪费大量ATP只产生微量GDP的过程。

 

合理的数据操作应该怎样的

上图展示了微软在RIA与数据库交互上的宏伟构想:无论是Silverlight,WPF,Javascript,还是ASP.NET,WCF,它们都应该使用无差别的数据逻辑,能够直接访问到数据层面,而不需要通过一层类似“代理”的数据服务。

 

Microsoft .NET RIA Services将如何实现“合理”

以上就是.NET RIA Services的实现原理。开发者在ASP.NET端的数据处理类(本图中是HRService)继承自一个叫做DomainService的类,在里面实现一些数据操作。.NET RIA Services就会自动生成相应的客户端类(本图中是HRContext)。而在我们开发客户端的时候,我们就可以直接调用.NET RIA Services生成的那个类,直接操作数据层面。

 

入门实例:
在了解.NET RIA Services想要完成的任务及其具体实现方法后,我们可以开始通过实例的方式来体验一下了。

  1. 开发环境:Visual Studio 2008 SP1 ,Silverlight 3 Beta SDK ,Silverlight Tools 3.0 , Microsoft .NET RIA Services March '09 Preview , SQL Server 2005
  2. 在VS2008中新建Silverlight项目
  3. 将Silverlight连接到ASP.NET Server project上

    完成该步骤后的Solution Explorer如下图所示
  4. 在Web项目上单击右键,新建
  5. 选择SQL Server2005里的数据库和表。VS会帮我们生成一个ADO.NET的实体(Entity)。

    生成的文件后缀名为.edmx,如本例中的
  6. 编译整个Solution。
  7. 再次在Web项目上右击,新增本文的主角——Domain Service Class 。"Domain Service Class”这名字挺熟的吧?嗯,上文介绍过了。
     
    根据提示勾选需要的部分。在本例中,我们选择了Messages表作为实体,并选择”Enable editing”,这样在生成的类中会初始包括Get,Insert,Update,Delete 4个基本的实体操作方法
  8. 完成上面的操作后,会在Web项目下生成RdChat_DomainService.cs类。

    Code

    namespace RiaServices_1.Web
    {
        using System;
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.ComponentModel.DataAnnotations;
        using System.Linq;
        using System.Web.Ria;
        using System.Web.Ria.Data;
        using System.Web.DomainServices;
        using System.Data;
        using System.Web.DomainServices.LinqToEntities;


        // Implements application logic using the RdChatEntities context.
        // TODO: Add your application logic to these methods or in additional methods.
        [EnableClientAccess()]
        public class RdChat_DomainService : LinqToEntitiesDomainService<RdChatEntities>
        {

            // TODO: Consider
            // 1. Adding parameters to this method and constraining returned results, and/or
            // 2. Adding query methods taking different parameters.
            public IQueryable<Messages> GetMessages()
            {
                return this.Context.Messages;
            }

            public void InsertMessages(Messages messages)
            {
                this.Context.AddToMessages(messages);
            }

            public void UpdateMessages(Messages currentMessages, Messages originalMessages)
            {
                this.Context.AttachAsModified(currentMessages, originalMessages);
            }

            public void DeleteMessages(Messages messages)
            {
                if ((messages.EntityState == EntityState.Detached))
                {
                    this.Context.Attach(messages);
                }
                this.Context.DeleteObject(messages);
            }
        }
    }


  9. 再次编译整个Solution。
  10. 点击Show All Files,你会发现系统已经为你生成了客户端的类,放在了Generated_Code目录下。我们将它include进来。

    这个RiaServices_1.Web.g.cs,是服务端RdChat_DomainService.cs的对应客户端版本。它包含了所有服务端版本类中定义的方法、实体等,而可在客户端直接调用。它打代码如下:

    Code
    //------------------------------------------------------------------------------
    // 
    //     This code was generated by a tool.
    //     Runtime Version:2.0.50727.3053
    //
    //     Changes to this file may cause incorrect behavior and will be lost if
    //     the code is regenerated.
    // 
    //------------------------------------------------------------------------------

    namespace RiaServices_1.Web
    {
        using System;
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.ComponentModel.DataAnnotations;
        using System.Linq;
        using System.Runtime.Serialization;
        using System.Web.Ria.Data;
        using System.Windows.Ria.Data;
        
        
        [DataContract(Namespace="http://schemas.datacontract.org/2004/07/RiaServices_1.Web")]
        public sealed partial class Messages : Entity
        {
            
            private string _body;
            
            private string _name;
            
            private string _partitionKey;
            
            private string _rowKey;
            
            private Nullable<DateTime> _timestamp;
            
            [DataMember()]
            public string Body
            {
                get
                {
                    return this._body;
                }
                set
                {
                    if ((this._body != value))
                    {
                        this.ValidateProperty("Body", value);
                        this.RaiseDataMemberChanging("Body");
                        this._body = value;
                        this.RaiseDataMemberChanged("Body");
                    }
                }
            }
            
            [DataMember()]
            public string Name
            {
                get
                {
                    return this._name;
                }
                set
                {
                    if ((this._name != value))
                    {
                        this.ValidateProperty("Name", value);
                        this.RaiseDataMemberChanging("Name");
                        this._name = value;
                        this.RaiseDataMemberChanged("Name");
                    }
                }
            }
            
            [DataMember()]
            [Key()]
            public string PartitionKey
            {
                get
                {
                    return this._partitionKey;
                }
                set
                {
                    if ((this._partitionKey != value))
                    {
                        this.ValidateProperty("PartitionKey", value);
                        this.RaiseDataMemberChanging("PartitionKey");
                        this._partitionKey = value;
                        this.RaiseDataMemberChanged("PartitionKey");
                    }
                }
            }
            
            [DataMember()]
            [Key()]
            public string RowKey
            {
                get
                {
                    return this._rowKey;
                }
                set
                {
                    if ((this._rowKey != value))
                    {
                        this.ValidateProperty("RowKey", value);
                        this.RaiseDataMemberChanging("RowKey");
                        this._rowKey = value;
                        this.RaiseDataMemberChanged("RowKey");
                    }
                }
            }
            
            [DataMember()]
            public Nullable<DateTime> Timestamp
            {
                get
                {
                    return this._timestamp;
                }
                set
                {
                    if ((this._timestamp != value))
                    {
                        this.ValidateProperty("Timestamp", value);
                        this.RaiseDataMemberChanging("Timestamp");
                        this._timestamp = value;
                        this.RaiseDataMemberChanged("Timestamp");
                    }
                }
            }
            
            public override object GetIdentity()
            {
                return EntityKey.Create(this._partitionKey, this._rowKey);
            }
        }
        
        public sealed partial class RdChat_DomainContext : DomainContext
        {
            
            #region Query root fields
            private static IQueryable<Messages> _MessagesQuery = new Messages[0].AsQueryable();
            #endregion
            
            /// 
            /// Default constructor.
            /// 
            public RdChat_DomainContext() : 
                    base(new HttpDomainClient(new Uri("DataService.axd/RiaServices_1-Web-RdChat_DomainService/", System.UriKind.Relative)))
            {
            }
            
            /// 
            /// Constructor used to specify a data service URI.
            /// 
            /// 
            /// The RdChat_DomainService data service URI.
            /// 
            public RdChat_DomainContext(Uri serviceUri) : 
                    base(new HttpDomainClient(serviceUri))
            {
            }
            
            /// 
            /// Constructor used to specify a DomainClient instance.
            /// 
            /// 
            /// The DomainClient instance the DomainContext should use.
            /// 
            public RdChat_DomainContext(DomainClient domainClient) : 
                    base(domainClient)
            {
            }
            
            public EntityList<Messages> Messages
            {
                get
                {
                    return this.Entities.GetEntityList<Messages>();
                }
            }
            
            #region Query root properties
            public static IQueryable<Messages> MessagesQuery
            {
                get
                {
                    return _MessagesQuery;
                }
            }
            #endregion
            
            #region LoadMessages method overloads
            /// 
            /// Invokes the server-side method 'GetMessages' and loads the result into .
            /// 
            [LoadMethod(typeof(Messages))]
            public void LoadMessages(IQueryable<Messages> query, MergeOption mergeOption, object userState)
            {
                base.Load("GetMessages", null, query, mergeOption, userState);
            }
            
            /// 
            /// Invokes the server-side method 'GetMessages' and loads the result into .
            /// 
            [LoadMethod(typeof(Messages))]
            public void LoadMessages()
            {
                this.LoadMessages(null, MergeOption.KeepCurrentValues, null);
            }
            
            /// 
            /// Invokes the server-side method 'GetMessages' and loads the result into .
            /// 
            [LoadMethod(typeof(Messages))]
            public void LoadMessages(IQueryable<Messages> query, object userState)
            {
                this.LoadMessages(query, MergeOption.KeepCurrentValues, userState);
            }
            #endregion
            
            protected override EntityContainer CreateEntityContainer()
            {
                return new RdChat_DomainContextEntityContainer();
            }
            
            internal sealed class RdChat_DomainContextEntityContainer : EntityContainer
            {
                
                public RdChat_DomainContextEntityContainer()
                {
                    this.CreateEntityList<Messages>(EntityListOperations.All);
                }
            }
        }
    }

  11. 打开Silverlight项目的 ,我们放入一些控件,做简单的界面。
    包括一个DataGrid ,TextBox和Button。在按钮中添加Click方法。

    UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  x:Class="RiaServices_1.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Width="640" Height="450">
        Grid x:Name="LayoutRoot" Background="White">
            StackPanel Orientation="Vertical"  Height="420">
                data:DataGrid x:Name="dataGrid" >data:DataGrid>
                StackPanel Orientation="Horizontal" Height="25">
                    TextBox x:Name="txtMsg" Text=" " Width="580"  >TextBox>
                    Button x:Name="btnSend" Content="发送消息"  Click="btnSend_Click"  >Button>
                StackPanel>
            StackPanel>
        Grid>
    UserControl>

  12. 在MainPage.xaml后台对应的cs文件 中,写入初始方法和处理按钮点击的方法。
    初始时,将所有已有的数据绑定到DataGrid中。
    点击Click方法后,将添加一条新数据到数据库,并刷新外观使新数据显示出来。
    在这个过程中,我们直接使用.NET RIA Services为你生成的客户端版本数据处理类了!很爽吧?

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using RiaServices_1.Web;

    namespace RiaServices_1
    {
        public partial class MainPage : UserControl
        {
            public MainPage()
            {
                InitializeComponent();
                RdChat_DomainContext context = new RdChat_DomainContext();
                dataGrid.ItemsSource = context.Messages;
                context.LoadMessages();

            }

            private void btnSend_Click(object sender, RoutedEventArgs e)
            {
                Messages msg=new Messages();
                msg.Body=txtMsg.Text;
                msg.Name="匿名用户";
                msg.PartitionKey = Guid.NewGuid().ToString();
                msg.RowKey = "slChat";
                msg.Timestamp = DateTime.Now;
                RdChat_DomainContext context = new RdChat_DomainContext();
                context.Messages.Add(msg);
                context.SubmitChanges();
                dataGrid.ItemsSource = context.Messages;
                context.LoadMessages();
            }
        }
    }

  13. F5  运行之!

 

怎样?非常方便吧?其实这只是一个非常简易的实例而已, .NET RIA Services还包括了许许多多强大的功能,包括metadata,shared code等等等等,请感兴趣的读者自行阅读SDK吧,那是一件非常享受的事情。

现在让我们再次回过头来看Shareach前几天写的那个Silverlight+WCF聊天程序,如果他用上.NET RIA Services的话,是不是会容易很多呢?

 

___________肌肉萎缩的分割线_________

本例源代码:

RiaServices_1.rar

时间: 2024-09-20 09:04:20

艾伟:Microsoft .NET RIA Services快速上手的相关文章

Microsoft .NET RIA Services快速上手

在MIX 09上,Nikhil Kothari发布了微软的一神作--Microsoft .NET RIA Services.虽然目前的版本仅仅是可怜的"March '09 Preview",但它已经足够让人兴奋不已.简单地说,在这之前,如果你用到了现在的RIA技术比如Silverlight,你只能选择写大量的服务或者WCF来实现数据的操作功能:而有了.NET RIA Services,你在RIA项目上操作数据,就像ASP.NET那样方便! Nikhil Kothari在MIX09上介绍

Win8强大兼容性无需适应快速上手

  如果说使用Win7是在一个我们熟悉的环境中操作,那么Win8就是给我们带来了两个激动人心的环境,一个是新颖的"开始"屏幕及它的应用生态,还有一个就是我们熟悉的跟Win7一样的桌面系统.这也就意味着Win8具有很强的兼容性,可以毫不费力地运行Win7的程序,轻松上手无压力. 其实一个操作系统做到Windows这样,基本也不用太多的在意兼容性问题了.作为一个使用最广泛的操作系统,任何软件厂商都会千方百计地向其靠拢,以便能在新系统上运行它们的程序,这是一个向上兼容的过程. Win8不仅仅

DirectX9 3D 快速上手 5

DirectX9 3D 快速上手  5By sssa2000     这一章的内容相对很简单,控制Mesh的移动,旋转等等,其实这一切都是在对矩阵进行操作.在 DX中,用到的变换有3种,一种是基于Word坐标系的,一种是基于View坐标系的,还有一种是基于投影的变换.而这些变换都是通过矩阵的运算来实现的,在.Net的托管环境下,实现这些操作相对于非托管来说简单一写,不用对矩阵的每个值运算. 关于矩阵的运算和变换的关系,很多文章都有分析,GameRes也有很多这样的好文章,例如:http://de

DirectX9 3D快速上手 3

DirectX9 3D快速上手 3 By sssa2000 4/15/2005 我们这里暂时先跳过,乏味的索引缓冲和深度缓冲的内容,先看看怎么在3D空间中实现一个东西,给自己来点成就感. 正好SDK的向导也是这么安排的,呵呵,那我们就继续从向导出发吧,以Tutorial 3为例子. 这个例子主要讲解运用变换矩阵来实现物体的变换,学过图形学或者线性代数的肯定就很容易理解,没学过的,找点这方面的资料看看就可以了. 先看看这个例子实现了什么,编译运行,噢,相比前面两个例子,有耳目一新的感觉,一个三角形

快速上手Java编程

Java语言是一种优秀的高级编程语言,在使用各种不同解决方案进行简单试 验的时候,允许我们够接近我们想要解决的问题.然而在平时的计算(和开发) 中,很多情况下"迅速准备一个Java 程序"来执行任务不是不切实际就是太花 时间.本文将您带入了 FESI(免费 EcmaScript解释程序)的秘密世界.在那里 ,用快速上手的方式展开 Java语言是一个标准,而非异议. 从概念到产品, Java 平台和 Java 编程语言都能提供其它开发环境中所没 有的高级功能和全面的 API,从而推进软件

mvc-MVC和wcf没有任何项目经验的情况下,怎么快速上手?

问题描述 MVC和wcf没有任何项目经验的情况下,怎么快速上手? MVC和wcf没有任何项目经验的情况下,怎么在新工作中快速上手? 解决方案 code.msdn.microsoft.com上有例子程序,下载下来看. 解决方案二: 我觉的可以网上啊github上面找点人家开源的写的不错的项目来看看,或者去那些在线学习平台上面看看视频,我觉的看视频学习还是很快的 解决方案三: 看已有代码,改写,然后自己写

Consuming Hidden WCF RIA Services

 原文 http://codeseekah.com/2013/07/05/consuming-hidden-wcf-ria-services/ A Silverlight application made it to my desk yesterday, an application that consumed a remote WCF RIA service running on a Microsoft IIS. The service did not provide a public API

一起谈.NET技术,LINQ to SQL快速上手 step by step

前言       最近接连遇到几个朋友问我同一个问题,就是关于.NET平台上ORM框架的选择.我想在这个讲求效率的时代,谁也不想手写SQL或存储过程去访问数据库了.大家都知道,在Java平台上,ORM这一块基本是Hibernate的天下.当然,相对轻量级的iBatis也有不错的表现.      不过谈到.NET平台,ORM框架似乎相对混乱了点.很多朋友问我的时候,往往会这样问:NHibernate.NBear和Castle该选择哪个?而当我反问:为什么不适用微软自带的Linq to Sql呢?对

Eclipse快速上手Hibernate--4. 继承映射(3)

继承     前两篇文章<Eclipse快速上手Hibernate--4. 继承映射(1) >和<继承映射(2)>中已经谈了每个类层次结构一个表(table per class hierarchy)与每个子类一个表(table per subclass)的策略,这篇文章主要说的是每个具体类一个表(table per concrete class).一些重复的部分这里就不说了,请参考前两篇文章.    这个策略很简单,抽象的基类不参与映射,具体子类参与映射.  1. 创建项目 ·