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 或更高版本。