程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Microsoft .NET RIA Services快速上手

Microsoft .NET RIA Services快速上手

編輯:關於.NET

在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想要完成的任務及其具體實現方法後,我們可以開始通過實例的方式來體驗一下了。

開發環境:Visual Studio 2008 SP1 ,Silverlight 3 Beta SDK ,Silverlight Tools 3.0 , Microsoft .NET RIA Services March '09 Preview , SQL Server 2005

在VS2008中新建Silverlight項目

將Silverlight連接到ASP.NET Server project上。

完成該步驟後的Solution Explorer如下圖所示

在Web項目上單擊右鍵,新建

選擇SQL Server2005裡的數據庫和表。VS會幫我們生成一個ADO.NET的實體(Entity)。

生成的文件後綴名為.edmx,如本例中的

編譯整個Solution。

再次在Web項目上右擊,新增本文的主角——Domain Service Class 。"Domain Service Class”這名字挺熟的吧?嗯,上文介紹過了。

根據提示勾選需要的部分。在本例中,我們選擇了Messages表作為實體,並選擇”Enable editing”,這樣在生成的類中會初始包括Get,Insert,Update,Delete 4個基本的實體操作方法

完成上面的操作後,會在Web項目下生成RdChat_DomainService.cs類。

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);
        }
    }
}

再次編譯整個Solution。

點擊Show All Files,你會發現系統已經為你生成了客戶端的類,放在了Generated_Code目錄下。我們將它include進來。

這個RiaServices_1.Web.g.cs,是服務端RdChat_DomainService.cs的對應客戶端版本。它包含了所有服務端版本類中定義的方法、實體等,而可在客戶端直接調用。它打代碼如下:

//------------------------------------------------------------------------------
// <auto-generated>
//     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.
// </auto-generated>
//------------------------------------------------------------------------------

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

        /// <summary>
        /// Default constructor.
        /// </summary>
        public RdChat_DomainContext() :
                base(new HttpDomainClient(new Uri("DataService.axd/RiaServices_1-Web-RdChat_DomainService/", System.UriKind.Relative)))
        {
        }

        /// <summary>
        /// Constructor used to specify a data service URI.
        /// </summary>
        /// <param name="serviceUri">
        /// The RdChat_DomainService data service URI.
        /// </param>
        public RdChat_DomainContext(Uri serviceUri) :
                base(new HttpDomainClient(serviceUri))
        {
        }

        /// <summary>
        /// Constructor used to specify a DomainClient instance.
        /// </summary>
        /// <param name="domainClient">
        /// The DomainClient instance the DomainContext should use.
        /// </param>
        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
        /// <summary>
        /// Invokes the server-side method 'GetMessages' and loads the result into <see cref="Messages"/>.
        /// </summary>
        [LoadMethod(typeof(Messages))]
        public void LoadMessages(IQueryable<Messages> query, MergeOption mergeOption, object userState)
        {
            base.Load("GetMessages", null, query, mergeOption, userState);
        }

        /// <summary>
        /// Invokes the server-side method 'GetMessages' and loads the result into <see cref="Messages"/>.
        /// </summary>
        [LoadMethod(typeof(Messages))]
        public void LoadMessages()
        {
            this.LoadMessages(null, MergeOption.KeepCurrentValues, null);
        }

        /// <summary>
        /// Invokes the server-side method 'GetMessages' and loads the result into <see cref="Messages"/>.
        /// </summary>
        [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);
            }
        }
    }
}

打開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>

在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();
        }
    }
}

F5  運行之!

怎樣?非常方便吧?其實這只是一個非常簡易的實例而已, .NET RIA Services還包括了許許多多強大的功能,包括metadata,shared code等等等等,請感興趣的讀者自行閱讀SDK吧,那是一件非常享受的事情。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved