Wcf Restful Service服务搭建
- 目的
使用Wcf(C#)搭建一个Restful Service
- 背景
最近接到一个项目,客户要求使用Restful 方式接收到数据,并对数据提供对数据的统计显示功能,简单是简单,但必须要使用Restful方式,客户端传递数据就必须使用Rest ful的格式的url,提交方式为Post。
其实在之前的公司里边就开发过一个restful服务,但只记得自己使用的wcf,而今已经忘记的差不多了,还以为只是简单的搭建一个wcf就可以,今天起初就创建了一个wcf项目,发现wcf项目http://localhost:6001/Test.svc好像很让人纠结就是这个url就是多出一个。svc,wsd什么之类的,根本就不是restful,后来上网上搜到原来我们之前不是用的简单的wcf工程,而是通过Wcf rest service template工程创建的。
- 创建Wcf rest service template工程:
在vs 新建工程-》online templates-》在搜索框中输入Wcf rest service template-》
创建好工程的工程:
- 这个工程值得注意的有以下地方:
1, Gobal.asax文件中的代码:
1 public class Global : HttpApplication 2 { 3 void Application_Start(object sender, EventArgs e) 4 { 5 RegisterRoutes(); 6 } 7 8 private void RegisterRoutes() 9 { 10 // Edit the base address of Service1 by replacing the "Service1" string below 11 RouteTable.Routes.Add(new ServiceRoute("Service1", new WebServiceHostFactory(), typeof(Service1))); 12 } 13 }
这里边是注册了url访问 route,这个访问格式就包含一下集中restful访问类型:
2.访问方式
备注:我默认的url host url为:http://localhost:6001/
访问url:http://localhost:6001/Service1 提交方式:GET 调用函数为:GetCollection
访问url:http://localhost:6001/Service1 提交方式:POST 调用函数为:Create
访问url:http://localhost:6001/Service1/1 提交方式:Get 调用函数为:Get(...)
访问url:http://localhost:6001/Service1/1 提交方式:PUT 调用函数为:Update(...)
访问url:http://localhost:6001/Service1/1 提交方式:PUT 调用函数为:Delete(...)
3.怎么注册访问方式
[WebGet(UriTemplate = "")]
List<SampleItem> GetCollection()
[WebInvoke(UriTemplate = "", Method = "POST")]
SampleItem Create(SampleItem instance)
[WebGet(UriTemplate = "{id}")]
SampleItem Get(string id)
[WebInvoke(UriTemplate = "{id}", Method = "PUT")]
SampleItem Update(string id, SampleItem instance)
[WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
void Delete(string id)
其实我们可以注意到这些"访问url"访问到的“调用的函数”上的注解:
指定了访问url为:http://localhost:6001/Service1
WebGetAttribute:
a. 决定了提交方式为Get,
b. UriTemplate ,决定了是否在http://localhost:6001/Service1后边追加其他路径
c. 其他参数RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Json等
WebInvokeAttribute
a.UriTemplate ,决定了是否在http://localhost:6001/Service1后边追加其他路径
b.Method,决定了提交方式,可选参数包含Get,Post,Put,Delete,当然也支持Header等其他方式。
c. 其他参数RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Json等
- 关于请求、返回数据格式
REST被受到欢迎原因:
1,分布式架构
2,请求、返回格式支持xml,json。
3,支持异步请求/提交数据,这使得Javascript可以轻松调用RESTful服务。
A.如果手动配置请求、返回数据格式?
wcf rest service template内置了简单的注册方式:在上边我们提到的WebGetAttribute,WebInvokerAttribute中都支持参数RequestFormat,ResponseFormat,可以手动的在代码中制定他们的参数类型:
1 // Summary: 2 // An enumeration that specifies the format of Web messages. 3 public enum WebMessageFormat 4 { 5 // Summary: 6 // The XML format. 7 Xml = 0, 8 // 9 // Summary: 10 // The JavaScript Object Notation (JSON) format. 11 Json = 1, 12 }
B.如果动态配置请求、返回数据格式?
相比手动配置之下,动态选择格式还是更灵活。打开之前创建的项目,在web.config中,设置:
<standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
将automaticFormatSelectionEnabled设置为true
设置后,我们就可以通过url访问到当前我们可以访问的路径接口等.
-
测试客户端
比如我们Restful Service代码如下:
[WebInvoke(UriTemplate = "Servlet", Method = "POST", ResponseFormat = WebMessageFormat.Json)] public string Welcome() { try { // 接收传递的参数信息 string param= HttpContext.Current.Request["param"]; // do somthing // 返回成功操作状态信息 return "{\"status\": 0, \"msg\": \"操作成功!\"}"; } catch (Exception ex) { // 返回失败操作状态信息 return "{\"status\": 1, \"msg\": \"操作失败!\"}"; ; } }
客户端调试:
static void Main(string[] args) { NameValueCollection responseEntity = new NameValueCollection(); responseEntity.Add("param", "1"); string baseUrl = "http://localhost:6001/TestReceiver/Welcome"; try { WebClient webClient = new WebClient(); // 采取POST方式必须加的header,如果改为GET方式的话就去掉这句话即可 webClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); // 得到返回字符流 byte[] responseData = webClient.UploadValues(baseUrl, "POST", responseEntity); // 解码返回值 string byRemoteInfo = Encoding.UTF8.GetString(responseData); Console.WriteLine(byRemoteInfo); } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); } Console.ReadKey(); }
上边我们采用的接收参数的方式是HttpContext.Current.Request.Params["param"]的方式来接收参数,确切说,这种方式在vs的调试模式下是可以接收到参数的,但是在iis上就不是这么好说了(具体问题,我不是太清楚是不是因为我的服务器上没有注册WCF组建的方式(验证方案参考:http://blog.csdn.net/findsafety/article/details/9045721),还是其他问题;具体原因我暂时不能去确认,服务器远程不了,只能明天去确认)。
- 服务器端在函数的参数中写入要接收的参数信息,作为函数的参数,这种方式是可行的。
demo:
1 public class Global : HttpApplication 2 { 3 void Application_Start(object sender, EventArgs e) 4 { 5 RegisterRoutes(); 6 } 7 8 private void RegisterRoutes() 9 { 10 // Edit the base address of Service1 by replacing the "Test" string below 11 RouteTable.Routes.Add(new ServiceRoute("Test", new WebServiceHostFactory(), typeof(Test))); 12 } 13 } 14 15 [ServiceContract] 16 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] 17 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] 18 // NOTE: If the service is renamed, remember to update the global.asax.cs file 19 public class Test 20 { 21 private Logger logger = LogManager.GetCurrentClassLogger(); 22 23 [WebInvoke(UriTemplate = "Login", Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest)] 24 public bool Login(string userName, string userPassword) 25 { 26 //模拟登录,实际使用时需数据库访问 27 if (userName == "huangbo" && userPassword == "123") 28 { 29 return true; 30 } 31 return false; 32 } 33 } 34 35 public class UserInfo 36 { 37 public string userName { get; set; } 38 public string userPassword { get; set; } 39 } 40 41 class Program 42 { 43 static void Main(string[] args) 44 { 45 string baseUrl = "http://localhost:6001/Test/Login"; 46 47 UserInfo info = new UserInfo 48 { 49 userName = "11", 50 userPassword = "222" 51 }; 52 53 //先访问LoginService,得到授权 54 var request = (HttpWebRequest)WebRequest.Create(baseUrl); 55 request.ContentType = "application/json;charset=utf-8"; 56 request.Method = "POST"; 57 request.KeepAlive = true; 58 //request.ClientCertificates.Add(cert); 59 //使用JSON.NET将对象序列化成JSON字符串 60 var requestBody = Newtonsoft.Json.JsonConvert.SerializeObject(info); 61 byte[] databytes = Encoding.UTF8.GetBytes(requestBody); 62 request.ContentLength = databytes.Length; 63 using (var writer = request.GetRequestStream()) 64 { 65 writer.Write(databytes, 0, databytes.Length); 66 } 67 var response = request.GetResponse(); 68 using (var stream = response.GetResponseStream()) 69 { 70 using (var reader = new StreamReader(stream)) 71 { 72 Console.WriteLine(reader.ReadToEnd()); 73 } 74 } 75 } 76 } 77
参考资料:
http://www.cnblogs.com/xiarifeixue/archive/2011/04/27/restful.html
http://www.cnblogs.com/bearhb/archive/2012/07/11/2586412.html
怎么接收参数:
UserInfo info = new UserInfo
{
userName = “user”,
userPassword = “pwd”
};
string strJson=Newtonsoft.Json.JsonConvert.SerializeObject(message);
byte[] jsonBytes=Encoding.UTF8.GetBytes(strJson);
test client post method: json string UploadData(string url,string method,byte[] bytes);
webClient.UploadData("url","Post",jsonBytes);
mapping WCF Rest Service method:
[WebInvoke(UriTemplate = "", Method = "POST",BodyStyle=WebMessageBodyStyle.WrappedRequest)]
基础才是编程人员应该深入研究的问题,比如:
1)List/Set/Map内部组成原理|区别
2)mysql索引存储结构&如何调优/b-tree特点、计算复杂度及影响复杂度的因素。。。
3)JVM运行组成与原理及调优
4)Java类加载器运行原理
5)Java中GC过程原理|使用的回收算法原理
6)Redis中hash一致性实现及与hash其他区别
7)Java多线程、线程池开发、管理Lock与Synchroined区别
8)Spring IOC/AOP 原理;加载过程的。。。
【+加关注】。