添加ReplyToUser对象,更新实体层。
贡献值排行榜,查看我的排行。
查看我评论过的信息,我的发布信息的评论。
评论推送通知,wcf安全认证。
下面就是开发过程中遇到的一些问题,以及解决方案:
前言
一直想为社会做一点事情,却一直都不知道做什么,策划已久的"人人监督"app终于做了一小半了。
这是我的第五款app了,可从在博文记录在开发app中遇到的问题和技术,这次"人人监督"不能在错过了,一定要坚持把整个开发历程写下来, 从 调研 到 app策划 到 数据库设计 到 UI设计 和 代码编写 到 测试 到 上架到微软商店, 同大家分享在代码世界中的快乐。
"人人监督" 是一款供民众投诉、检举、监督的一款app,其目的是人人监督以营造和谐的社会!
项目技术
开发环境:Windows8 + Visual Studio 2012 + SQl Server 2008
服务器端:EntityFramework6 + WCFService
客户端:WIndowsPhone8、8.1
框架:MVVM
策划
在笔记本上,手写的,有时间再抄下来!
开发历程
到目前位置已经完成的功能模块:
(按照开发的顺序)
1.整个APP的服务端
2.客户端信息列表展示
3.省市列表
4.发布检举监督信息(可上传图片)
5.登录
6.注册
7.个人信息 (I want to say)
8.信息评论页面
遇到的问题
起先准备用ashx(一般处理程序)来写服务端的,可一般处理程序就是很一般。
跟朋友交流后,发现问题远远没有我想象的简单,要考虑的问题太多了:比如传输协议用什么,用户信息安全,数据加密,服务端访问权限等等。
考虑再三决定用wcf,因为之前有项目中用过,只会一点点基础用法。
原本以为wcf只是一个类似webservice的很简单的服务,入手后发现仅wcf的配置就够你琢磨一段时间的。
咱们是程序员嘛,不怕,有的是头脑,再三摸索后,发现默认的配置可以供wp使用,唉。
下面就列出遇到的问题:
1.wcf配置问题
在使用wcf的时候一定要为每个操作添加特性供客户端调用,在接口上添加[ServiceContract],行为上添加[OperationContract],如果供web调用,还要加一个特性[WebGet]。
还有wcf的binding,系统提供的绑定以及binding的介绍可以看这里http://msdn.microsoft.com/zh-cn/library/ms730879(v=vs.110).aspx,当时不知道怎么搜关键字,搜了好久才找到。
还有默认binding的属性配置http://msdn.microsoft.com/zh-cn/library/ms731361(v=vs.110).aspx。
还有其他的问题已经记不清了,反正当时是写了很多个demo,有asp.net的,wpf的,Console的,sliverlight的各种测试,查阅了csdn和msdn论坛,才搞定的。
还有wcf exception处理还没搞懂,总之有时间一定要把wcf系统性的看一遍。
2.wcf的寄宿方式和访问
我用的IIS,发布到IIS后,如果端口不是80,会出现经常访问不了情况。这个时候可以在防火墙添加入站规则,将该端口允许外界访问,这个问题也是折腾了好一番。(具体配置有时间会单独写一篇博文记录:IIS网站配置端口允许外部设备访问)
3.wcf返回结果序列化
ef中有个虚拟加载项,一些导航属性不能被序列化,这个时候将延迟加载的对象加上DataContract和DataMember特性就OK了,这里也涉及到了wcf中的契约。(具体情况会单独写一篇博文:wcfservice返回集合对象的序列化)
4.wcf的安全性
一切准备就绪,服务写好了,发布到了IIS了,客户端可以正常引用了。可问题又来了,一旦服务器地址泄漏,那别人就不也可以引用的我的wcf么?
经过一番资料查询后,看到了几种解决方案,有两种我觉得是靠谱的,第一个是安全证书,第二个是自己写验证。
安全证书那玩意好像很高级,我选择了第二种,相比后者而言会简单更好理解,就是在每次请求服务器的时候添加一个Header信息,在头部信息中带一个用户名和密码。
到了wcfservice服务器后在进行判断,不匹配就直接抛出一个您没有权限访问的异常。相比虽然简单,但是这个比较繁琐,要在每个方法内部都进行一个判断。(以后有时间我会研究一下安全证书,研究完后我会写一篇:关于wcfservice的安全认证的博文)
5.图片上传
wcfservice接收wp8传过来的图片保存的时候要么拒绝访问,要么找不到目录。这样即可:var path = AppDomain.CurrentDomain.BaseDirectory + "Images"; (有时间会单独写一篇博文:WP8通过WCFService上传图片)
6.接收对 http://localhost:1613/Service.svc 的 HTTP 响应时发生错误。这可能是由于服务终结点绑定未使用 HTTP 协议造成的。这还可能是由于服务器中止了 HTTP 请求上下文(可能由于服务关闭)所致。有关详细信息,请参见服务器日
如果此次请求了一个对象,对象中包含了一个集合,将该集合从Collection改为List,并且添加[DataMember]特性。
7.获取用户当前的所在的城市,在wp里只可以获取到经纬度,无法通过经纬度获取城市,如果有大神有好的办法还请赐教,目前我用的是第三方根据IP来获取地理位置的。
我用的是新浪的api:http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js
//获取当前地址的 API UriBuilder urlbuilder = new UriBuilder("http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js"); //创建 HttpWebRequest 对象 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlbuilder.Uri); //异步调用 IAsyncResult result = request.BeginGetResponse(ResponseCallback, request);
回掉函数
void ResponseCallback(IAsyncResult result) { try { //获取异步返回的信息 HttpWebRequest request = (HttpWebRequest)result.AsyncState; //创建 HttpWebResponse 对象 HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result); //读取文件流 using (StreamReader reader = new StreamReader(response.GetResponseStream())) { //Json 串 String strJson = @reader.ReadToEnd().Replace("var remote_ip_info = ", "").Replace(";", ""); Byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strJson); using (MemoryStream ms = new MemoryStream(buffer)) { //调用 DataContractJsonSerializer 解析Json var address = new Address(); DataContractJsonSerializer serializer = new DataContractJsonSerializer(address.GetType()); address = (Address)serializer.ReadObject(ms); var proxy = new ServiceClient(); proxy.GetCityByNameAsync(address.city); proxy.GetCityByNameCompleted += ((s, e) => { App.RootFrame.Dispatcher.BeginInvoke(() => { this.CurrentCity = e.Result; if (e.Result == null) this.CurrentCity = new T_City() { CityID = 0, CityName = "无法获取当前位置" }; }); }); } } } catch { } }
将项目中使用的SqlServer数据库改为MySql数据库
眼看所有的功能都做好了,今天准备部署,发现服务器的数据库是MySql,顿时泪奔,搞了一个下午终于搞定 [擦汗] 。
将SqlServer数据库改成MySql数据库的步骤如下:
1.将项目中的所有EntityFramework.SqlServer.dll引用移除
2.将Data层和Client层添加分别添加MySql.Data和MySql.Data.Entity.EF6 这两个类库 (对应项目中的EF版本)
3.在Client层的config文件中配置MySql的链接字符串记得添加providerName="MySql.Data.MySqlClient"
<add name="SupervisionDB" connectionString="Server=localhost;Port=3306;DataBase=SupervisionDB;uid=root;pwd=a123" providerName="MySql.Data.MySqlClient" />
运行后会出现以下异常:
未经处理的异常: System.InvalidOperationException: No Entity Framework provider found for the ADO.NET provider with invariant name 'MySql.Data.MySqlClient'. Make sure the prov
ider is registered in the 'entityFramework' section of the application config file. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.
提示找不到MySql.Data.MySqlClient的处理程序,将EFContent.cs中的
[DbConfigurationType(typeof(System.Data.Entity.DbConfiguration))] 改为 [DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]即可。
在次运行,如果报 error 0040: The Type nvarchar(max) is not qualified with a namespace or alias. Only primitive types can be used without qualification
如下图
此时只需要将Data层的Migrations的文件夹删掉即可。因为SqlServer做过一些迁移,有些数据类型与MySql不兼容。
添加服务引用出错:
错误 4 自定义工具错误: 无法生成服务引用“GTBServiceReference”的代码。请检查其他错误和警告信息,了解详细信息。
解决办法:在服务上右键,选择"编辑服务配置"中的"重新引用程序集中的类型"勾去掉。
服务器的环境配置以及WCF部署到IIS:
服务器:WindowsServer2008
在服务器管理器的角色中添加IIS,根据自己需求选IIS的功能项。
为了支持wcf,在服务器管理器的功能中右键添加功能,将WCF激活项和子项勾选,如下图。
MySql中文乱码:
在连接字符串中加入:Charset:utf8; 这里应该跟创建数据库的时候指定的字符集一致!
WIndowsServer2008配置MySql Proxy:
MySql Proxy的下载地址:http://dev.mysql.com/downloads/mysql-proxy/,选择Windows版本。
下载后解压,进入CMD命令找到mysql-proxy的bin目录,也可以将bin目录配置到环境变量,以下命令是已经配置了环境变量的写法:
如果没有配置环境变量,将binPath后面的mysql-proxy改为mysql proxy的bin目录 例如 ...bin/mysql-proxy
sc create "ProxyTonge" DisplayName= "MySQL ProxyTonge" start= "auto" binPath= "mysql-proxy --proxy-address=0.0.0.0:3306 --proxy-backend-addresses=1.1.1.1:3306"
注意1.1.1.1:3306就是云数据库的IP地址
这里还需要注意的是一定要cmd命令框来执行,不然会出现