SilverlightDesktop.net 介绍






4.11/5 (4投票s)
SilverlightDesktop.net 是一个开源的 ASP.NET 框架,允许您将 Silverlight 模块动态加载到可调整大小、可拖动的窗口中。

引言
注意:您应始终从 http://SilverlightDesktop.net 下载最新版本的 SilverlightDesktop.net。
SilverlightDesktop.net 是一个开源的 ASP.NET 框架,允许您将 Silverlight 模块动态加载到可调整大小、可拖动的窗口中。它还可以加载没有窗口的模块,以便轻松集成到现有网站中。SilverlightDesktop.net 可作为独立程序和 DotNetNuke™ 版本使用。
本文将探讨以下主题
- 什么是 SilverlightDesktop 以及为什么我需要使用它?
- 安装
- 特点
- 安全
- 自定义模块
- 安装模块
- 自定义模块开发
- 核心
- SilverlightDesktop 项目
- 可移动的可拖动窗口
- SilverlightCore 项目
- 电子邮件
- 日志记录
- SilverlightDesktop.net for DotNetNuke™
什么是 SilverlightDesktop 以及为什么我需要使用它?
Microsoft Silverlight 在客户端运行;也就是说,它不在 Web 服务器上运行,而是在用户的 Web 浏览器中运行。您必须有一种方法来在启动 Silverlight 应用程序的 Web 服务器与用户 Web 浏览器中运行的 Silverlight 应用程序之间进行通信。这种通信通常通过 Web 服务执行。
创建 Silverlight 应用程序时,您可能会发现需要安全、用户管理、电子邮件和日志记录。实现这些支持性元素可能比创建 Silverlight 应用程序本身需要更多时间。

SilverlightDesktop.net 提供了一个框架,允许您创建只包含所需自定义功能的模块。SilverlightDesktop.net 负责安全、用户和角色管理,同时还提供电子邮件和日志记录支持。
安装 SilverlightDesktop.net
要安装或升级 SilverlightDesktop.net
- 创建数据库
- 将 SilverlightDesktop 安装文件解压缩到硬盘上的一个目录中
- 配置 IIS Web 服务器以指向该目录(或在 Visual Studio 2008 中打开该目录并运行应用程序以使用其内置 Web 服务器)
- 在 Web 浏览器中打开该站点并按照向导完成安装

可以在以下链接中找到进一步的安装说明
- 在 Vista 上使用 IIS 安装 SilverlightDesktop
- 使用 Visual Studio 2008 安装 SilverlightDesktop
- 将 Silverlight Desktop 升级到最新版本
- 安装或升级 SilverlightDesktop for DotNetNuke
SilverlightDesktop.net 功能
当您使用安装期间创建的用户名和密码登录 SilverlightDesktop.net 管理界面时,您将可以访问其功能

- 一个密码保护的管理部分,允许您配置诸如允许的密码尝试次数和电子邮件设置等选项。
- 一个用户管理器,允许您创建和编辑用户,并设置他们的角色和活动状态。
- 模块设置,允许您配置您创建或上传的模块。您可以在 SilverlightDesktop.net 网站上找到要上传的模块。
- 多个您可以创建和配置的桌面实例。AutoLoad 模块功能允许显示单个模块而无需可移动的可调整大小的窗口。
- 应用程序日志为管理员提供应用程序事件的概述
SilverlightDesktop.net 安全性
安全性实现如下

SilverlightDesktop.net 启动 Silverlight 控件。它使用代码传递 InitParameters,其中包含临时密码(它还存储 IP 地址)。
string strIPAddress = this.Context.Request.UserHostAddress;
int intPassword = Authendication.SetSilverlightKey(_UserID, strIPAddress);
string strWebServiceBase = GetWebServiceBase();
SilverlightDesktop.InitParameters =
    String.Format("PortalID={0},ModuleId={1},UserID={2}," + 
      "Password={3},WebServiceBase={4},AutoLoadModule={5}",
      "-1", _DesktopID.ToString(), _UserID.ToString(), 
      intPassword.ToString(), strWebServiceBase, AutoLoadModule);
在 SilverlightDesktop 项目(创建包含其他 Silverlight 模块加载的窗口的 Silverlight 应用程序)的 App.xaml.cs 文件中,代码检索参数...
private void Application_Startup(object sender, StartupEventArgs e)
{
    // Load the main control
    this.RootVisual = new Page(e.InitParams["PortalID"], 
        e.InitParams["ModuleId"], 
        e.InitParams["UserID"], 
        e.InitParams["Password"], 
        e.InitParams["WebServiceBase"], 
        e.InitParams["AutoLoadModule"]);
}
...并将它们传递给 Silverlight 自定义模块(当自定义模块被动态加载时)。它通过自定义模块的 .Tag 属性传递参数。
private void loadAssembly(Stream s)
{
    // from http://silverlight.net/forums/p/14941/49437.aspx (BlueAquarius)
    // From http://joel.neubeck.net/2008/03/
    //          silverlight-how-to-on-demand-assembly-deployment/
    try
    {
        Uri uri = new Uri(strXAPName.Replace(".xap", ".dll"), UriKind.Relative);
        StreamResourceInfo xapPackageSri = new StreamResourceInfo(s, null);
        StreamResourceInfo assemblySri = Application.GetResourceStream(xapPackageSri, uri);
        AssemblyPart assemblyPart = new AssemblyPart();
        Assembly a = assemblyPart.Load(assemblySri.Stream);
        UserControl objUserControl = (UserControl)a.CreateInstance(strAssemblyClassName);
        if (objUserControl == null)
        {
            debug("objUserControl is null " + strAssemblyClassName);
            return;
        }
      // Pass the parameters to the control that it will need to connect to the website
        objUserControl.Tag = string.Format("{0}, {1}, {2}, {3}, {4}", 
          intPortalID, intModuleId, intUserID, strPassword, strWebServiceBase);
        if (UseWindows)
        {
            SilverlightWindowControl objSilverlightWindowControl = 
              new SilverlightWindowControl(objSilverlightDesktopModule.WindowSize);
            objSilverlightWindowControl.Window.Content = objUserControl;
            objSilverlightWindowControl.WindowName.Text = 
                             objSilverlightDesktopModule.ModuleName;
            Canvas.SetLeft(objSilverlightWindowControl, (double)intWindowLocation);
            Canvas.SetTop(objSilverlightWindowControl, (double)intWindowLocation);
            this.LayoutRoot.Children.Add(objSilverlightWindowControl);
        }
        else
        {
            this.LayoutRoot.Children.Add(objUserControl);
        }
    }
    catch (Exception ex)
    {
        debug("Exception when loading the assembly part:");
        debug(ex.ToString());
    }
}
当自定义模块调用 Web 服务时,会传递临时密码给 Web 服务。
#region ShowWhoAmI
private void ShowWhoAmI()
{
    BasicHttpBinding bind = new BasicHttpBinding();
    EndpointAddress MyEndpointAddress = 
      new EndpointAddress(strWebServiceBase + "WhoAmI.asmx");
    var proxy = new WhoAmISoapClient(bind, MyEndpointAddress);
    proxy.WhoIAmCompleted += 
      new EventHandler<whoiamcompletedeventargs>(proxy_WhoIAmCompleted);
    proxy.WhoIAmAsync(intPortalID, intModuleId, intUserID, strPassword);
}
void proxy_WhoIAmCompleted(object sender, WhoIAmCompletedEventArgs e)
{
    UserInfo UserInfo = (UserInfo)e.Result;
    DisplayWhoIAm(UserInfo);
}
private void DisplayWhoIAm(UserInfo UserInfo)
{
    this.txtFirstName.Text = UserInfo.FirstName;
    this.txtLastName.Text = UserInfo.LastName;
    this.txtEmail.Text = UserInfo.Email;
}
#endregion

Web 服务将此临时密码以及调用它的 Silverlight 应用程序的 IP 地址(请记住,Silverlight 应用程序在用户的 Web 浏览器中运行)传递给 **SilverlightDesktopCore** 项目中的 Authentication 类。
#region WhoIAm
[WebMethod(Description = "WhoIAm")]
[ScriptMethod()]
public UserInfo WhoIAm(int PortalID, int ModuleId, int UserID, string Password)
{
    string strIPAddress = this.Context.Request.UserHostAddress;
    SilverlightDesktopAuthendicationHeader 
      SilverlightDesktopAuthendicationHeader = 
        new SilverlightDesktopAuthendicationHeader();
    SilverlightDesktopAuthendicationHeader.PortalID = PortalID;
    SilverlightDesktopAuthendicationHeader.UserID = UserID;
    SilverlightDesktopAuthendicationHeader.Password = Password;
    SilverlightDesktopAuthendicationHeader.ModuleId = ModuleId;
    SilverlightDesktopAuthendicationHeader.IPAddress = strIPAddress;
    UserInfo response = new UserInfo();
    Authendication Authendication = 
       new Authendication(SilverlightDesktopAuthendicationHeader);
    if (Authendication.IsUserValid("WhoAmI"))
    {
        response = Authendication.GetUserInfo();
    }
    else
    {
        response.FirstName = "Visitor";
        response.LastName = DateTime.Now.ToLongDateString();
    }
    return response;
}
#endregion
Authentication 类比较用户名和密码以确定用户是否应被身份验证(注意:Strings.Left(result.IPAddress,6) 用于仅匹配 IP 地址的前一部分,以防用户位于代理服务器后面,代理服务器会不断更改 IP 地址)。
//  Get the SilverlightKey
var SilverlightKey = 
  (from ASilverlightDesktopUser in SilverlightDesktopDAL.SilverlightDesktopUsers
   where ASilverlightDesktopUser.UserID == _UserID
   select ASilverlightDesktopUser).FirstOrDefault();
if (SilverlightKey.SilverlightKey == ConvertToSilverlightkey(_Password) & 
    Strings.Left(SilverlightKey.IPAddress, 6) == Strings.Left(_IPAddress, 6))
{
    return true;
}
else
{
    if (Strings.Left(SilverlightUser.IPAddress,6) == Strings.Left(_IPAddress,6))
    {
        // The correct IP address was used
        // To prevent a brute force attack scramble the password
        // A hacker is now chasing a moving target
        SetSilverlightKey();
    }
    return
}
每次用户登录 SilverlightDesktop.net 站点时,都会获得一个新的临时密码。
自定义模块

可以通过上传 .zip 文件来安装模块。软件包清单在此处描述:创建模块包。
自定义模块开发
自定义模块是通过创建生成 .xap 文件的 Silverlight 项目来创建的。

.xap 文件存储在 SilverlightDesktop 网站的 ClientBin 目录中。也可以创建 Web 服务和数据访问层等其他模块元素。

使用管理界面中的模块设置来配置模块。有关创建模块的更多信息可以在 此链接 找到。
核心

SilverlightDesktop.net 源代码包含五个项目
- SilverlightDesktop_Web - 此项目包含用户与之交互的网站。该网站包含在 SilverlightDesktop.net 的“安装版本”中。
- SilverlightDesktop - 此项目包含动态加载 Silverlight 自定义模块并可选地将其放置在可移动的可调整大小的窗口中的 Silverlight 项目。
- SilverlightDesktopCore - 此项目包含身份验证、电子邮件和日志记录功能。自定义模块中的服务器端代码也可以引用此项目。
- WhoAmI - 一个示例 Silverlight 自定义模块,用于显示当前登录用户的身份。
- wsWhoAmI - WhoAmI 示例自定义模块的示例 Web 服务项目。
SilverlightDesktop 项目

SilverlightDesktop 项目被编译成 SilverlightDesktop.xap,并驻留在 SilverlightDesktop 网站的 ClientBin 目录中。当访问者查看他们的 SilverlightDesktop 或 **AutoLoad** 模块时,它会被加载。在 SilverlightDesktop 窗口模式下显示模块时,该项目会加载模块定义中指定的类,在 SilverlightWindowControl 中。

SilverlightWindowControl 由一组 Canvas 控件、Rectangle 控件和 Window 控件组成,这些控件被排列成一个可调整大小的窗口控件。事件处理程序已连接到各种元素,以支持拖动和调整大小的功能。
以下是用于操作左侧的代码
#region LeftSide
private void LeftSide_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    //Start Drag
    FrameworkElement LeftSide = (FrameworkElement)sender;
    LeftSide.CaptureMouse();
    // Set the starting point for the drag
    StartingDragPoint = e.GetPosition(LeftSide);
    Point ControlPoint = e.GetPosition(this);
    StartingDragPoint.X = StartingDragPoint.Y - ControlPoint.Y - .5;
    LeftSide.MouseMove += new MouseEventHandler(LeftSide_MouseMove);
    LeftSide.MouseLeftButtonUp += 
      new MouseButtonEventHandler(LeftSide_MouseLeftButtonUp);
}
void LeftSide_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    //Stop Drag
    FrameworkElement LeftSide = (FrameworkElement)sender;
    LeftSide.ReleaseMouseCapture();
    LeftSide.MouseMove -= new MouseEventHandler(LeftSide_MouseMove);
    LeftSide.MouseLeftButtonUp -= 
      new MouseButtonEventHandler(LeftSide_MouseLeftButtonUp);
}
void LeftSide_MouseMove(object sender, MouseEventArgs e)
{
    Point LeftSidePoint = e.GetPosition(LeftSide);
    double PointDifference = LeftSidePoint.X - StartingDragPoint.X;
    if (PointDifference < 0)
    {
        PointDifference = PointDifference * -1;
        if (LeftSidePoint.X < (Window.Width + (PointDifference) - 60))
        {
            this.SetValue(WidthProperty, (double)(PointDifference));
            Window.SetValue(WidthProperty, (double)Window.Width + (PointDifference));
            DragStackPanel.SetValue(WidthProperty, 
               (double)DragStackPanel.Width + (PointDifference));
            DragBar.SetValue(WidthProperty, (double)DragBar.Width + (PointDifference));
            TopSide.SetValue(WidthProperty, (double)TopSide.Width + (PointDifference));
            BottomSide.SetValue(WidthProperty, 
               (double)BottomSide.Width + (PointDifference));
            Canvas Canvas = (Canvas)this.Parent;
            Point Point = e.GetPosition(Canvas);
            Canvas.SetLeft(this, Point.X - StartingDragPoint.X);
            Canvas.SetLeft(RightSide, (double)TopSide.Width + StartingDragPoint.X);
        }
    }
    else
    {
        if (LeftSidePoint.X < (Window.Width - (PointDifference) - 60))
        {
            this.SetValue(WidthProperty, (double)(PointDifference));
            Window.SetValue(WidthProperty, (double)Window.Width - (PointDifference));
            DragStackPanel.SetValue(WidthProperty, 
               (double)DragStackPanel.Width - (PointDifference));
            DragBar.SetValue(WidthProperty, (double)DragBar.Width - (PointDifference));
            TopSide.SetValue(WidthProperty, (double)TopSide.Width - (PointDifference));
            BottomSide.SetValue(WidthProperty, 
                      (double)BottomSide.Width - (PointDifference));
            Canvas Canvas = (Canvas)this.Parent;
            Point Point = e.GetPosition(Canvas);
            Canvas.SetLeft(this, Point.X - StartingDragPoint.X);
            Canvas.SetLeft(RightSide, (double)TopSide.Width + StartingDragPoint.X);
        }
    }
}
#endregion
SilverlightDesktopCore 项目

SilverlightDesktopCore 项目由主 SilverlightDesktop 网站使用,但自定义模块也可以引用它。

SilverlightDesktopCore 项目中可用的一些类和方法如上所示。
它为自定义模块提供的核心功能包括身份验证、日志记录
// Log the event
ApplicationLog.AddToLog(String.Format("Module: {0} - File deleted {1}.", 
   objModules.FirstOrDefault().ModuleName, strFileToDelete));
以及电子邮件
#region Send Test Email
protected void lnkTestEmail_Click(object sender, EventArgs e)
{
    string[] arrAttachments = new string[0];
    string strEmailResponse = Email.SendMail(txtSMTPFrom.Text.Trim(), 
      txtSMTPFrom.Text.Trim(), "", "", 
      txtSMTPFrom.Text.Trim(), MailPriority.Normal, 
      "SilverlightDesktop Email", Encoding.UTF8, 
      "A test email sent from SilverlightDesktop",
      arrAttachments, txtSMTPEmailServer.Text.Trim(), 
      rbAuthendication.SelectedValue, txtSMTPUsername.Text.Trim(), 
      txtSMTPPassword.Text.Trim(), chkSecureAccess.Checked);
    lblUpdated.Text = (strEmailResponse.Trim() == "") ? 
                       "Email Sent." : strEmailResponse;
}
#endregion
SilverlightDesktop.net for DotNetNuke™
SilverlightDesktop.net 也提供了一个在 DotNetNuke™ 中运行的版本。更多信息可以在此处找到
注意:两个版本都需要 ASP.NET 3.5 或更高版本以及 SQL Server(或 Express)2005 或更高版本。


