[SL] Silverlight + WCF Demo项目
I:项目描述:利用 Silverlight+WCF 技术,模拟资源管理器(如图1)功能,通过地址栏输入本地文件夹路径,然后将解析出来的该目录下所有文件(夹)存储到数据库中,然后再加载到界面上显示出来;
(图1)
II:涉及技术:Silverlight + WCF + Component One 控件(TreeView 和 FlexGrid)
III:开发环境:Visual Studio2012 + SQL Server 2008 R2 + Silverlight 5 + Component One C1Silverlight_2014v1;
一 项目架构(如图2)
(图2)
FolderDB:DAL(数据访问层),包括文件属性类 Folders,文件夹树模型类 FolderModel,数据库操作类 DBHelper;
FolderUI:Silverlight 客户端,基本界面显示,包括 FlexGrid 标题数据源类 ColumnHeaders,文件大小值转换类 FileSizeConverter;
FolderWCF:WCF 服务层,包括 FolderService 服务类;
FolderWeb:Web层,该项目中涉及不多;
二 源码部分解析
/// <summary>
/// 执行多条SQL语句,实现数据库事务
/// </summary>
/// 多条SQL语句
public int ExecuteSqlTran(List sqlStrList)
{
SqlTransaction sqlTran = null;
try
{
if (ConnectionState.Open != m_SqlConn.State)
{
m_SqlConn.Open();
}
int count = 0;// 影响的记录数
SqlCommand cmd = new SqlCommand();
sqlTran = m_SqlConn.BeginTransaction();
cmd.Connection = m_SqlConn;
cmd.Transaction = sqlTran;
foreach (string sqlStr in sqlStrList)
{
if (sqlStr.Trim().Length > 1)
{
cmd.CommandText = sqlStr;
count += cmd.ExecuteNonQuery();
}
}
sqlTran.Commit();// 提交数据库事务
return count;
}
catch (SqlException sqlEx)
{
if (null != sqlTran)
{
sqlTran.Rollback();// 失败后回滚
} throw new Exception(sqlEx.Message);
}
}
注意执行完 ExecuteNonQuery() 后,并不算完,事务在最后还需要进行提交数据库事务才行,sqlTran.Commit(),否则操作一直都不会执行,但是调试过程中也不会出现异常;
public class FolderModel
{
/// <summary>
/// 当前目录(文件夹)属性
/// </summary>
public Folders CurrFolder { get; set; } /// <summary>
/// 子文件(夹)集合
/// </summary>
public ObservableCollection SubFolders { get; set; } public FolderModel()
{
SubFolders = new ObservableCollection();
} public FolderModel(Folders folders)
{
CurrFolder = folders;
SubFolders = new ObservableCollection();
}
}
这是绑定 C1TreeView 控件的数据源模型,其中 ObservableCollection 是表示一个动态数据集合,在添加项、移除项或刷新整个列表时,此集合将提供通知。SubFolders 则是作为子树的绑定,CurrFolder 则是作为当前节点的绑定,详细见下面的 XAML 代码解释;
/// <summary>
/// Header数据源
/// </summary>
public class ColumnHeader : INotifyPropertyChanged
{
private List m_HeaderList;
public event PropertyChangedEventHandler PropertyChanged;
public List HeaderList
{
get
{
return m_HeaderList;
}
set
{
m_HeaderList = value;
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs("HeaderList"));
}
}
}
}
该类作为 C1FlexGrid 列标题即 Column.Header 的动态绑定数据源,HeaderList 中存储的是每列的列名;该数据会从 WCF 服务端获取,然后绑定在客户端上显示;
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
int byteSize = int.Parse(value.ToString());// 单位字节
int nKBSize = (int)Math.Ceiling(byteSize * 1.0 / 1024);// 转换成KB return string.Format("{0} KB", nKBSize);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
因为要将文件大小该列的值全部由字节转换成 KB,则将 Size 那一列绑定该转换器即可;
- ItemsSource="{Binding SubFolders}" // 绑定 SubFolders 数据源,该数据源在 FolderModel 类中定义,作为树数据源;
- ItemTemplate="{StaticResource FolderTemplate}" // 指定树每个节点的模版定义;静态资源 FolderTemplate 则是在<UserControl.Resources>标签中定义;
- HierarchicalDataTemplate:// 定义 TreeView 节点模版
- ItemsSource="{Binding SubFolders}" // 同样指定该模版数据源
- <TextBlock Text="{Binding CurrFolder.Name}" /> // 节点所包含的内容,绑定 CurrFolder 对象中 Name 属性值,在 FolderModel 类中定义;
C1FlexGrid控件:
AutoGenerateColumns="False" //绑定数据源中有些列数据并不想显示出来,只要求部分指定的列显示,则需要设置成 false,阻止其自动生成列;
<c1:C1FlexGrid.Columns> // 设置每列所绑定的数据
<c1:Column Binding="{Binding [2]}" HorizontalAlignment="Left" Width="200">
<c1:Column.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=HeaderList[2]}" />
</DataTemplate>
</c1:Column.HeaderTemplate>
</c1:Column>
该树绑定的数据源类型为 List<List<string>>,所以 Binding 的对象就是 List<string> 类型,而按以往的思路,Binding 的对象是具有 get,set 的属性,查看了 List 类下有 public T this[int index] { get; set; },所以可以直接通过 [n] 索引来绑定数据;
HeaderTemplate 作为 Header 的模版定义,绑定的数据源类型是 ColumnHeader,直接访问其属性 HeaderList 即可;
添加文件夹树节点单击事件,在 FlexGrid 中加载该文件夹下所有文件信息;
// 文件夹目录上的选择单个文件夹事件
private void FoldersTree_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
C1TreeViewItem selectedNode = tvFoldersTree.SelectedItem;
if (null != selectedNode)
{
// 当前选择的节点
FolderModel selectedFolderModel = (FolderModel)selectedNode.Header;
m_SelectedFolderName = selectedFolderModel.CurrFolder.Name;// 节点名称(文件夹名)
m_WCFClient.GetFilesAsync(selectedFolderModel.CurrFolder.ID);
}
} void GetFilesCompleted(object sender, GetFilesCompletedEventArgs e)
{
if (null == e.Error)
{
List<List<string>> result = e.Result;
ColumnHeader columnHeader = new ColumnHeader();
columnHeader.HeaderList = result[0];
fgFilesView.ColumnHeaders.DataContext = columnHeader;// 绑定列标题数据源 result.RemoveAt(0);// 移除第一个表示列名称的List
fgFilesView.ItemsSource = new PagedCollectionView(result);// 绑定列内容数据源
fgFilesView.Columns[3].ValueConverter = new FileSizeConverter();
txtMsg.Text = "加载文件夹【" + m_SelectedFolderName + "】目录下的文件已完成。";
}
else
{
txtMsg.Text = "加载文件数据失败,异常信息:" + e.Error.Message;
}
}
C1TreeView 的节点是 C1TreeViewItem 类型,所以获得当前点击的节点可以用:C1TreeViewItem selectedNode = tvFoldersTree.SelectedItem; 当然也可以由 sender 转型得到;值得注意的是,在这里,C1TreeViewItem 的 Header 属性是 C1TreeView 所绑定数据源的类型,即 FolderModel,而在 xaml 文件中,对 Column 标签的 header 属性进行值绑定时,其 header 值为 string 类型!!故在 xaml 中对 header 的绑定是通过 HeaderTemplate 模版定义来完成的;
服务器端返回的 e.Result 是一个 List<List<string>> 类型,其中第一个 List<string> 指的是列名;列名的绑定方式:fgFilesView.ColumnHeaders.DataContext = columnHeader; C1FlexGrid 的绑定方式:fgFilesView.ItemsSource = new PagedCollectionView(result); 其中 DataContext 和 ItemsSource 两种是有区别的,本人还没有学习到,读者可以阅读他人的相关博文学习;
对第三列的文件大小需要绑定值转换器:fgFilesView.Columns[3].ValueConverter = new FileSizeConverter(); 即可;
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IFolderService" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:54416/FolderService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IFolderService"
contract="FolderServiceRefer.IFolderService" name="BasicHttpBinding_IFolderService" />
</client>
</system.serviceModel>
</configuration>
ServiceReferences.ClientConfig
该文件是由 Silverlight 客户端添加服务引用时自动生成的配置文件,其中 <bindings> 标签内容是由 WCF 服务器端的 Web.config 配置文件中对应的 <bindings> 标签内容截取部分而来,对于 maxBufferSize 和 maxReceivedMessageSize 两个属性最好设置值大一些,而且必须值一样,不能超过 2147483647;否则会报如下异常:
1:“由于正在缓冲消息,MaxReceivedMessageSize 和 MaxBufferSize 的值必须相同”;
2:发生了 System.ServiceModel.ProtocolException
Message=已超过传入消息(65536)的最大消息大小配额。若要增加配额,请使用相应绑定元素上的MaxReceivedMessageSize属性。
Source=System.ServiceModel
StackTrace:
在System.ServiceModel.Channels.HttpInput.ThrowHttpProtocolException(String messagem, HttpStatusCode statusCode, String statusDescription)
<endpoint> 是客户端终结点设置,address 属性指 WCF 所在服务器端的访问路径,其他属性内容也是从服务器端 Web.config 配置文件中自动生成过来的;
三 项目遇到的问题及参考解决方法
1:WCF 的独立调试
参考解决方法:将 WCF 项目“设为启动项目”,并将 svc 文件“设为起始页”,然后按“F5”即可打开“WCF测试客户端”,如下图,然后选择要是调试的方法(如SaveFolders()),在右侧的“值”中填入所需参数(字符串里需要转义),再执行“调用”即可在“响应”中看到结果值;如果在 VS 中相应的方法中加入断点,则可以进行断点调试操作!
2:WCF 测试客户端的配置文件
参考解决方法:上图中,在“配置文件”上右键选择“用 SvcConfigEditor 进行编辑”选项,即可对 WCF 测试客户端的配置文件进行修改;
尤其是出现“已超过传入消息(65536)的最大消息大小配额。”的异常信息时,需要修改其中“绑定”目录下已定义的 basicHttpBinding 属性配置信息,将其中的 MaxBufferPoolSize 和 MaxBufferSize 和 MaxReceivedMessageSize 的值均改为 int 的 MaxValue 即可;
还有,每次打开该 SvcConfigEditor,程序都会自动重新加载“个人文件夹\AppData\Local\Temp\Test Client Projects\11.0\f868aff1-aa2d-4418-abaf-f4be03a71529”下的 Client.dll.config 配置文件,f868aff1-aa2d-4418-abaf-f4be03a71529 这个根据情况会有所变动,这样之前的属性配置修改就白搭了,每次启动都要修改,这丫的肯定不干了呀,在 WCF 测试客户端里,在“工具”-》“选项”中,把“始终在启动服务时重新生成配置”选项去掉就欧克了!
3:没有异常,重新生成解决方案也都成功,但是启动 Silverlight 后界面上完全空白
参考解决方法:毫无头绪的 bug 呀,而且是深藏不露的!通过启动 Web 端的界面也无法显示 Silverlight 程序,而且查看了 Silverlight 中 xaml 文件下也无异常情况,此时此刻,可以肯定的是加载 Silverlight 过程中出错了,没有正常加载Silverlight!但是又如何知道是什么 bug,什么地方出现了 bug 呢?
在 Web 项目中找到要加载 Silverlight 应用程序的 aspx 页面文件,将 onSilverlightError 该函数内的 errMsg 错误信息弹出显示即可;
这时候再根据错误提示去找度娘就简单多了,2103的错误解决如下:
由于在修改 Silverlight 客户端的命名空间时,导致项目内部没有彻底完全的修改完命名空间,才会导致2103错误;在 Silverlight 项目右键属性中,查看“启动对象”是否是修改命名空间后的选项即可;
4:在 Silverlight 客户端添加服务引用时,异常“找不到类型 Project.Web.Service,它在 ServiceHost 指令中提供为 Service 特性值,或在配置元素...”
如果,我说的是如果,你已经完全确定你的 WCF 服务完全正确,Web.config 配置里也完全正确,那这个错误只可能是因为你在 WCF 项目中编辑完服务之后,没有对 WCF 项目“重新生成”导致的!!这也提醒着大家,在项目编码过程中,每次对 WCF 项目进行编辑修改后,都要重新生成一下,并且在 Silverlight 客户端的服务上右键“更新服务引用”才行,不然你改了半天的 WCF 服务端方法,结果执行的结果依然让人寒心,那就真的寒心了... ...
5:项目的部署问题
VS 默认是采用自带的 IIS Express 来部署 Silverlight 项目以及 WCF 服务,部署后在右下角会出现如下图标和内容;
关于 IIS Express 和本地的 IIS 的区别,是一个很有意思的话题,这里就不说了,建议去看大神博客解析,会受益匪浅的。这里简单提及一些基本的关于 IIS Express 知识:
配置文件:C:\Program Files\IIS Express\AppServer\applicationhost.config
<applicationPools> 标签 ---- 应用程序池配置
<add name="Clr4IntegratedAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
相当于 IIS 中
<sites> 标签 ---- 网站配置,每一个 <site> 子标签,代表一个网站的配置
<site name="Development Web Site" id="1" serverAutoStart="true">
<application path="/">
<virtualDirectory path="/" physicalPath="%IIS_BIN%\AppServer\empty_wwwroot" />
</application>
<bindings>
<binding protocol="http" bindingInformation=":8080:localhost" />
</bindings>
</site>
<defaultDocument> 标签 ---- 设置默认起始页
<files>
<add value="Default.htm" />
<add value="Default.asp" />
<add value="index.htm" />
<add value="index.html" />
<add value="iisstart.htm" />
<add value="default.aspx" />
</files>
其他的可以自行了解去了!
Silverlight+WCF 部署在本地 IIS 上,需要注意事项:
1)WCF 项目和 SilverlightWeb 项目发布到 IIS 网站下的相同目录下,
2:作为第二次发布的项目,不能选择“发布前删除所有现有文件”,否则会把前一个发布的文件清除了;
3:发布目录下的配置文件 Web.config 检查一下是不是WCF项目中的配置文件,如果不是,手动粘贴过来覆盖
4:修改 ClientBin\*.xap\ServiceReferences.ClientConfig 文件中,关于WCF服务地址的终结点配置,改为本地 ip 地址;
5:应用程序“DEFAULT WEB SITE”中的服务器错误;HTTP 错误 403.14-Forbidden;Web服务器被配置为不列出此目录的内容。
因为部署的项目中没有默认的启动页面,IIS 设置的默认启动页面文档包括【“Default.htm”,“Default.asp”,“index.htm”,“index.html”,“iisstart.htm”,default.aspx】,而你部署的项目根目录下没有这些文档中的至少一个,而且,在 IIS 功能视图中的“目录浏览”设置里也禁用了,所以报此错误!解决方法自己去搞定吧!!
6:直接访问 svc 服务文件(http://192.168.0.64/FolderService.svc)报如下异常:
当前已禁用此服务的元数据发布。
如果之前在 VS 上调试一切正常,只是发布后出现这个问题,去发布目录下查看配置文件 Web.config,看是否是 WCF 项目下的那个配置文件,不是的话就手动拷贝覆盖。
否则的话就按浏览器下面出现的异常提示解决:
[SL] Silverlight + WCF Demo项目的更多相关文章
- [silverlight—wcf]参数:调试资源字符串不可用,秘钥和参数通常提供足够的信息用以诊断问题。
这段时间在做一个项目,有一项需求是上传,经过思考之后,决定采取Silverlight+WCF的方式做上传操作.就在项目做完了之后,本地测试也都没问题,发布到服务器上的时候,顿时就出现故障了.在选择文件 ...
- silverlight wcf mvvm
近期工作比較忙.也没有时间发表新内容,今天有点时间,就顺便写点,说说近期开发的一套系统心得. 我刚去这个公司已经将前端确定要用Silverlight,我不知道为什么要选择这个,或许是为以后转C/S系统 ...
- 如何使用npm构建一个react demo项目
方法一: 1) 安装node.js环境 点我进入nodejs官网 1.1) 下载LTS(Long term support)版本,安装 1.2) 在cmd中使用以下命令查看node是否安装成功 no ...
- Spring AOP 切面编程实战Demo项目
为什么会有此项目?在某日,我看博客时,看到了讲面向切面编程的内容,之前也知道spring是面向切面编程的,只是自己没有写过相关的代码,于是决定自己写一个test.但是url拦截器从外部看,和AOP有相 ...
- electron demo项目npm install安装失败解决办法
electron官网提供的demo项目,在npm install 的时候总是报错显示安装失败, 解决办法:FQ即可成功安装.
- Spring.net的Demo项目,了解什么是控制反转
Spring这个思想,已经推出很多年了. 刚开始的时候,首先是在Java里面提出,后来也推出了.net的版本. Spring里面最主要的就是控制反转(IOC)和依赖注入(DI)这两个概念. 网上很多教 ...
- Surging Demo 项目之一
原文:Surging Demo 项目之一 开发与运行环境 IDE Visual Stadio 2017/Visual Stadio 2019 Visual Stadio Core Docker 和 D ...
- demo项目开发(Python+flask+mysql+redis只包含后端接口)
[demo项目开发需求] 用户信息管理,可以注册.登录.添加用户.删除用户 注册:任何用户可以注册,对用户提交的注册信息进行校验,返回对应的信息,其中: 用户名:必填,唯一 密码:必填,只能6-12位 ...
- Unity3D Demo项目开发记录
前言 经过一段时间的学习与实际开发,unity3D也勉强算是强行入门了,正所谓好记性不如烂笔头,更何况本人并非专业从事unity3D开发,会一点C#但也并不熟悉,为了避免后期遗忘,因此特意整理了一个D ...
随机推荐
- 中间人攻击 -- Cookie 喷发
0x00 前言 分享个中间人攻击姿势,屡试不爽. 原本是篇老文,不过写的太啰嗦.今天用简明的文字,重新讲一遍. 0x01 原理 传统 cookie 嗅探,只能获得用户主动访问的站点.不访问就抓不到,效 ...
- 【php爬虫】百万级别知乎用户数据爬取与分析
代码托管地址:https://github.com/hoohack/zhihuSpider 这次抓取了110万的用户数据,数据分析结果如下: 开发前的准备 安装Linux系统(Ubuntu14.04) ...
- 在Visual Studio上开发Node.js程序
[题外话] 最近准备用Node.js做些东西,于是找找看能否有Visual Studio上的插件以方便开发.结果还真找到了一个,来自微软的Node.js Tools for Visual Studio ...
- 开发OpenWrt路由器上LuCI的模块
[题外话] 学校里最近改造了校园网,要求必须用iNode验证,万幸的是路由器能刷OpenWrt,并且OpenWrt上有好多iNode认证的开源项目,比如njit8021xclient(以下简称njit ...
- Golang与C#之switch区别
Golang与C#之switch区别 Go是Google开发的一种编译型,可并行化,并具有垃圾回收功能的编程语言. C#是微软公司发布的一种面向对象的.运行于.NET Framework之上的高级程序 ...
- Java 浅析三大特性之一封装
在说Java 三个特性之前,我们先了解一下什么是面向对象,以及为什么Java是面向对象的语言. 面向对象是区别于面向过程的一种编程的思想.我们可以通过这个例子冰箱装大象的例子来了解一下面向对象与面向过 ...
- ASP.NET MVC Routing学习笔记(一)
Routing在ASP.NET MVC中是非常核心的技术,属于ASP.NET MVC几大核心技术之一,在使用Routing之前,得先引入System.Web.Routing,但其实不用这么麻烦,因为在 ...
- Windows下安装python2和python3双版本
现在大家常用的桌面操作系统有:Windows.Mac OS.ubuntu,其中Mac OS 和 ubuntu上都会自带python.这里我们只介绍下Windows(我用的Win10)环境下的pytho ...
- SSISDB5:Parameter
Parameter 是Package 提供给外界的接口,通过传递不同的Parameter value,能够动态控制 Package 执行不同的Task或container,产生不同的结果. 一,Par ...
- 【Win10应用开发】相对布局(RelativePanel)
外面的雨下得很大,老周就决定雨下漫笔了. 今天咱们说一个新控件——RelativePanel.本质上,它就是一个面板,面板干啥用的?面板就是一个容器,里面可以放其他对象,就像我们小时候玩的七巧板一样, ...