• Restful风格wcf调用2——增删改查


    写在前面

    上篇文章介绍如何将wcf项目,修改成restful风格的接口,并在上面提供了查询的功能,上篇文章中也感谢园友在评论中的提的建议,自己也思考了下,确实是那个道理。在urltemplate中,定义的url确实不规范,虽然能实现功能,但是缺少点专业性。rest风格的请求,是通过post,delete,get,put等请求方法来区别的,而不是通过在url中取不同的名字来进行区别。这里再次感谢@~Js园友提醒。

    在这篇文章中将最新的代码贴出来,方便查看。

    系列文章

    Restful风格wcf调用 (其中代码中的uritemplate定义不规范,建议参考本文)

    代码示例

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.ServiceModel.Web;
    using System.Text;
    using System.Web.Script.Services;
    
    namespace Wolfy.WCFRestfuleDemo
    {
        // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
        [ServiceContract]
        public interface IUserService
        {
            /// <summary>
            /// 获得所有的用户信息
            /// </summary>
            /// <returns>json或者xml</returns>
            [OperationContract]
            [WebGet(UriTemplate = "api/users", ResponseFormat = WebMessageFormat.Xml)]
            List<UserInfo> QueryList();
            /// <summary>
            /// 根据id查询用户信息
            /// </summary>
            /// <param name="where"></param>
            /// <returns></returns>
            [OperationContract]
            [WebGet(UriTemplate = "api/users/{where}", ResponseFormat = WebMessageFormat.Json)]
            UserInfo Query(string where);
    
            /// <summary>
            /// 根据编号删除用户信息
            /// </summary>
            /// <param name="id"></param>
            /// <returns></returns>
            [OperationContract]
            [WebInvoke(UriTemplate = "api/users/{id}", Method = "DELETE", ResponseFormat = WebMessageFormat.Xml)]
            bool Delete(string id);
            /// <summary>
            /// 添加用户信息
            /// </summary>
            /// <param name="userInfo"></param>
            /// <returns></returns>
            [OperationContract]
            [WebInvoke(UriTemplate = "api/users", Method = "POST", ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Json)]
            bool Insert(UserInfo userInfo);
            /// <summary>
            /// 更新用户信息
            /// </summary>
            /// <param name="userInfo"></param>
            /// <returns></returns>
            [OperationContract]
            [WebInvoke(UriTemplate = "api/users", Method = "PUT", ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Json)]
            bool Update(UserInfo userInfo);
        }
    }
    复制代码

    修改的地方:uriTemplate,以名词组成,具体的操作通过Method谓词进行区分,另外参数中UserInfo,为其WebInvoke设置RequestFormat(请求数据类型)属性,设置为json格式的数据,这样在服务端介绍到数据后,系统内部将对齐进行反序列化为具体的实体类。还有合并按照id和name查询的接口,因为原来设置的uritemplate为api/users/{id}和api/users/{name}而且请求的方法都是get方法,无法区别到底调用哪个,所以将两个方法合并为了一个方法。
    1、删除Http(delete),根据id找到用户信息,并从集合中移除。

    复制代码
     1        /// <summary>
     2         /// 根据编号删除用户信息
     3         /// </summary>
     4         /// <param name="id"></param>
     5         /// <returns></returns>
     6         public bool Delete(string id)
     7         {
     8             //当前操作上下文
     9             WebOperationContext woc = WebOperationContext.Current;
    10             //状态码
    11             woc.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
    12             try
    13             {
    14                 if (string.IsNullOrEmpty(id))
    15                 {
    16                     throw new ArgumentNullException("id");
    17                 }
    18                 var users = QueryList();
    19                 int iId = Convert.ToInt32(id);
    20                 var user = users.Where(x => x.ID == iId).FirstOrDefault();
    21                 woc.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.Accepted;
    22                 return users.Remove(user);
    23             }
    24             catch (Exception ex)
    25             {
    26                 //异常 输出状态
    27                 woc.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.ExpectationFailed;
    28                 woc.OutgoingResponse.StatusDescription = ex.Message;
    29                 return false;
    30             }
    31         }
    复制代码

    2、添加Http(post),POST里的数据格式通过RequestFormat定义为Json,WCF框架接受到Json数据的请求,会自动反序列化成UserInfo实例。

    复制代码
     1         /// <summary>
     2         /// 添加用户信息
     3         /// </summary>
     4         /// <param name="userInfo"></param>
     5         /// <returns></returns>
     6         public bool Insert(UserInfo userInfo)
     7         {
     8             var users = QueryList();
     9             WebOperationContext woc = WebOperationContext.Current;
    10             woc.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
    11             try
    12             {
    13                 users.Add(userInfo);
    14                 woc.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.Created;
    15                 return true;
    16             }
    17             catch (Exception ex)
    18             {
    19                 //异常 输出状态
    20                 woc.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.ExpectationFailed;
    21                 woc.OutgoingResponse.StatusDescription = ex.Message;
    22                 return false;
    23             }
    24         }
    复制代码

    3、修改(Http/Put),根据id找到要修改的对象,对该对象重新赋值。

    复制代码
     1        /// <summary>
     2         /// 更新用户信息
     3         /// </summary>
     4         /// <param name="userInfo"></param>
     5         /// <returns></returns>
     6         public bool Update(UserInfo userInfo)
     7         {
     8             var users = QueryList();
     9             WebOperationContext woc = WebOperationContext.Current;
    10             try
    11             {
    12                 var user = users.Where(x => x.ID == userInfo.ID).FirstOrDefault();
    13                 if (user != null)
    14                 {
    15                     user = userInfo;
    16                     woc.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.Accepted;
    17                     return true;
    18                 }
    19                 else
    20                 {
    21                     woc.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
    22                     return false;
    23                 }
    24 
    25             }
    26             catch (Exception ex)
    27             {
    28                 //异常 输出状态
    29                 woc.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.ExpectationFailed;
    30                 woc.OutgoingResponse.StatusDescription = ex.Message;
    31                 return false;
    32             }
    33         }
    复制代码

    4、查询(http/get)

    复制代码
      /// <summary>
            /// 获得所有的用户信息
            /// </summary>
            /// <returns>json或者xml</returns>
            public List<UserInfo> QueryList()
            {
                return new List<UserInfo>() { 
                    new UserInfo() { ID = 1, Name = "wofly", Age = 22, Birthday = DateTime.Now, Gender = true }, 
                      new UserInfo() { ID = 2, Name = "san zhang", Age = 21, Birthday = DateTime.Now, Gender = true }, 
                        new UserInfo() { ID = 3, Name = "wukong sun", Age = 23, Birthday = DateTime.Now, Gender = false }, 
                          new UserInfo() { ID = 4, Name = "zi ma", Age = 45, Birthday = DateTime.Now, Gender = true }
                };
            }
    复制代码

    服务端的异常处理中通过 OutgoingResponse.StatusCode 返回不同的Code。

    查询成功 —— System.Net.HttpStatusCode.OK (默认)。

    创建成功 —— System.Net.HttpStatusCode.Created

    更新或者删除成功 —— System.Net.HttpStatusCode.Accepted

    当然,HttpStatusCode枚举不止这几个。感兴趣的可以查看这个枚举。你会发现,包揽了常见的一些状态枚举。

    复制代码
       // Summary:
        //     Contains the values of status codes defined for HTTP.
        public enum HttpStatusCode
        {
            // Summary:
            //     Equivalent to HTTP status 100. System.Net.HttpStatusCode.Continue indicates
            //     that the client can continue with its request.
            Continue = 100,
            //
            // Summary:
            //     Equivalent to HTTP status 101. System.Net.HttpStatusCode.SwitchingProtocols
            //     indicates that the protocol version or protocol is being changed.
            SwitchingProtocols = 101,
            //
            // Summary:
            //     Equivalent to HTTP status 200. System.Net.HttpStatusCode.OK indicates that
            //     the request succeeded and that the requested information is in the response.
            //     This is the most common status code to receive.
            OK = 200,
            //
            // Summary:
            //     Equivalent to HTTP status 201. System.Net.HttpStatusCode.Created indicates
            //     that the request resulted in a new resource created before the response was
            //     sent.
            Created = 201,
            //
            // Summary:
            //     Equivalent to HTTP status 202. System.Net.HttpStatusCode.Accepted indicates
            //     that the request has been accepted for further processing.
            Accepted = 202,
            //
            // Summary:
            //     Equivalent to HTTP status 203. System.Net.HttpStatusCode.NonAuthoritativeInformation
            //     indicates that the returned metainformation is from a cached copy instead
            //     of the origin server and therefore may be incorrect.
            NonAuthoritativeInformation = 203,
            //
            // Summary:
            //     Equivalent to HTTP status 204. System.Net.HttpStatusCode.NoContent indicates
            //     that the request has been successfully processed and that the response is
            //     intentionally blank.
            NoContent = 204,
            //
            // Summary:
            //     Equivalent to HTTP status 205. System.Net.HttpStatusCode.ResetContent indicates
            //     that the client should reset (not reload) the current resource.
            ResetContent = 205,
            //
            // Summary:
            //     Equivalent to HTTP status 206. System.Net.HttpStatusCode.PartialContent indicates
            //     that the response is a partial response as requested by a GET request that
            //     includes a byte range.
            PartialContent = 206,
            //
            // Summary:
            //     Equivalent to HTTP status 300. System.Net.HttpStatusCode.MultipleChoices
            //     indicates that the requested information has multiple representations. The
            //     default action is to treat this status as a redirect and follow the contents
            //     of the Location header associated with this response.
            MultipleChoices = 300,
            //
            // Summary:
            //     Equivalent to HTTP status 300. System.Net.HttpStatusCode.Ambiguous indicates
            //     that the requested information has multiple representations. The default
            //     action is to treat this status as a redirect and follow the contents of the
            //     Location header associated with this response.
            Ambiguous = 300,
            //
            // Summary:
            //     Equivalent to HTTP status 301. System.Net.HttpStatusCode.MovedPermanently
            //     indicates that the requested information has been moved to the URI specified
            //     in the Location header. The default action when this status is received is
            //     to follow the Location header associated with the response.
            MovedPermanently = 301,
            //
            // Summary:
            //     Equivalent to HTTP status 301. System.Net.HttpStatusCode.Moved indicates
            //     that the requested information has been moved to the URI specified in the
            //     Location header. The default action when this status is received is to follow
            //     the Location header associated with the response. When the original request
            //     method was POST, the redirected request will use the GET method.
            Moved = 301,
            //
            // Summary:
            //     Equivalent to HTTP status 302. System.Net.HttpStatusCode.Found indicates
            //     that the requested information is located at the URI specified in the Location
            //     header. The default action when this status is received is to follow the
            //     Location header associated with the response. When the original request method
            //     was POST, the redirected request will use the GET method.
            Found = 302,
            //
            // Summary:
            //     Equivalent to HTTP status 302. System.Net.HttpStatusCode.Redirect indicates
            //     that the requested information is located at the URI specified in the Location
            //     header. The default action when this status is received is to follow the
            //     Location header associated with the response. When the original request method
            //     was POST, the redirected request will use the GET method.
            Redirect = 302,
            //
            // Summary:
            //     Equivalent to HTTP status 303. System.Net.HttpStatusCode.SeeOther automatically
            //     redirects the client to the URI specified in the Location header as the result
            //     of a POST. The request to the resource specified by the Location header will
            //     be made with a GET.
            SeeOther = 303,
            //
            // Summary:
            //     Equivalent to HTTP status 303. System.Net.HttpStatusCode.RedirectMethod automatically
            //     redirects the client to the URI specified in the Location header as the result
            //     of a POST. The request to the resource specified by the Location header will
            //     be made with a GET.
            RedirectMethod = 303,
            //
            // Summary:
            //     Equivalent to HTTP status 304. System.Net.HttpStatusCode.NotModified indicates
            //     that the client's cached copy is up to date. The contents of the resource
            //     are not transferred.
            NotModified = 304,
            //
            // Summary:
            //     Equivalent to HTTP status 305. System.Net.HttpStatusCode.UseProxy indicates
            //     that the request should use the proxy server at the URI specified in the
            //     Location header.
            UseProxy = 305,
            //
            // Summary:
            //     Equivalent to HTTP status 306. System.Net.HttpStatusCode.Unused is a proposed
            //     extension to the HTTP/1.1 specification that is not fully specified.
            Unused = 306,
            //
            // Summary:
            //     Equivalent to HTTP status 307. System.Net.HttpStatusCode.RedirectKeepVerb
            //     indicates that the request information is located at the URI specified in
            //     the Location header. The default action when this status is received is to
            //     follow the Location header associated with the response. When the original
            //     request method was POST, the redirected request will also use the POST method.
            RedirectKeepVerb = 307,
            //
            // Summary:
            //     Equivalent to HTTP status 307. System.Net.HttpStatusCode.TemporaryRedirect
            //     indicates that the request information is located at the URI specified in
            //     the Location header. The default action when this status is received is to
            //     follow the Location header associated with the response. When the original
            //     request method was POST, the redirected request will also use the POST method.
            TemporaryRedirect = 307,
            //
            // Summary:
            //     Equivalent to HTTP status 400. System.Net.HttpStatusCode.BadRequest indicates
            //     that the request could not be understood by the server. System.Net.HttpStatusCode.BadRequest
            //     is sent when no other error is applicable, or if the exact error is unknown
            //     or does not have its own error code.
            BadRequest = 400,
            //
            // Summary:
            //     Equivalent to HTTP status 401. System.Net.HttpStatusCode.Unauthorized indicates
            //     that the requested resource requires authentication. The WWW-Authenticate
            //     header contains the details of how to perform the authentication.
            Unauthorized = 401,
            //
            // Summary:
            //     Equivalent to HTTP status 402. System.Net.HttpStatusCode.PaymentRequired
            //     is reserved for future use.
            PaymentRequired = 402,
            //
            // Summary:
            //     Equivalent to HTTP status 403. System.Net.HttpStatusCode.Forbidden indicates
            //     that the server refuses to fulfill the request.
            Forbidden = 403,
            //
            // Summary:
            //     Equivalent to HTTP status 404. System.Net.HttpStatusCode.NotFound indicates
            //     that the requested resource does not exist on the server.
            NotFound = 404,
            //
            // Summary:
            //     Equivalent to HTTP status 405. System.Net.HttpStatusCode.MethodNotAllowed
            //     indicates that the request method (POST or GET) is not allowed on the requested
            //     resource.
            MethodNotAllowed = 405,
            //
            // Summary:
            //     Equivalent to HTTP status 406. System.Net.HttpStatusCode.NotAcceptable indicates
            //     that the client has indicated with Accept headers that it will not accept
            //     any of the available representations of the resource.
            NotAcceptable = 406,
            //
            // Summary:
            //     Equivalent to HTTP status 407. System.Net.HttpStatusCode.ProxyAuthenticationRequired
            //     indicates that the requested proxy requires authentication. The Proxy-authenticate
            //     header contains the details of how to perform the authentication.
            ProxyAuthenticationRequired = 407,
            //
            // Summary:
            //     Equivalent to HTTP status 408. System.Net.HttpStatusCode.RequestTimeout indicates
            //     that the client did not send a request within the time the server was expecting
            //     the request.
            RequestTimeout = 408,
            //
            // Summary:
            //     Equivalent to HTTP status 409. System.Net.HttpStatusCode.Conflict indicates
            //     that the request could not be carried out because of a conflict on the server.
            Conflict = 409,
            //
            // Summary:
            //     Equivalent to HTTP status 410. System.Net.HttpStatusCode.Gone indicates that
            //     the requested resource is no longer available.
            Gone = 410,
            //
            // Summary:
            //     Equivalent to HTTP status 411. System.Net.HttpStatusCode.LengthRequired indicates
            //     that the required Content-length header is missing.
            LengthRequired = 411,
            //
            // Summary:
            //     Equivalent to HTTP status 412. System.Net.HttpStatusCode.PreconditionFailed
            //     indicates that a condition set for this request failed, and the request cannot
            //     be carried out. Conditions are set with conditional request headers like
            //     If-Match, If-None-Match, or If-Unmodified-Since.
            PreconditionFailed = 412,
            //
            // Summary:
            //     Equivalent to HTTP status 413. System.Net.HttpStatusCode.RequestEntityTooLarge
            //     indicates that the request is too large for the server to process.
            RequestEntityTooLarge = 413,
            //
            // Summary:
            //     Equivalent to HTTP status 414. System.Net.HttpStatusCode.RequestUriTooLong
            //     indicates that the URI is too long.
            RequestUriTooLong = 414,
            //
            // Summary:
            //     Equivalent to HTTP status 415. System.Net.HttpStatusCode.UnsupportedMediaType
            //     indicates that the request is an unsupported type.
            UnsupportedMediaType = 415,
            //
            // Summary:
            //     Equivalent to HTTP status 416. System.Net.HttpStatusCode.RequestedRangeNotSatisfiable
            //     indicates that the range of data requested from the resource cannot be returned,
            //     either because the beginning of the range is before the beginning of the
            //     resource, or the end of the range is after the end of the resource.
            RequestedRangeNotSatisfiable = 416,
            //
            // Summary:
            //     Equivalent to HTTP status 417. System.Net.HttpStatusCode.ExpectationFailed
            //     indicates that an expectation given in an Expect header could not be met
            //     by the server.
            ExpectationFailed = 417,
            //
            UpgradeRequired = 426,
            //
            // Summary:
            //     Equivalent to HTTP status 500. System.Net.HttpStatusCode.InternalServerError
            //     indicates that a generic error has occurred on the server.
            InternalServerError = 500,
            //
            // Summary:
            //     Equivalent to HTTP status 501. System.Net.HttpStatusCode.NotImplemented indicates
            //     that the server does not support the requested function.
            NotImplemented = 501,
            //
            // Summary:
            //     Equivalent to HTTP status 502. System.Net.HttpStatusCode.BadGateway indicates
            //     that an intermediate proxy server received a bad response from another proxy
            //     or the origin server.
            BadGateway = 502,
            //
            // Summary:
            //     Equivalent to HTTP status 503. System.Net.HttpStatusCode.ServiceUnavailable
            //     indicates that the server is temporarily unavailable, usually due to high
            //     load or maintenance.
            ServiceUnavailable = 503,
            //
            // Summary:
            //     Equivalent to HTTP status 504. System.Net.HttpStatusCode.GatewayTimeout indicates
            //     that an intermediate proxy server timed out while waiting for a response
            //     from another proxy or the origin server.
            GatewayTimeout = 504,
            //
            // Summary:
            //     Equivalent to HTTP status 505. System.Net.HttpStatusCode.HttpVersionNotSupported
            //     indicates that the requested HTTP version is not supported by the server.
            HttpVersionNotSupported = 505,
        }
    复制代码

    因为REST 是基于HTTP的, 所以对于 REST 的客户端的开发者,无法像使用传统的 WebService或者其他的WCF服务通过引用wsdl,享受“奢侈”的代码生成,而使用强类型的本地代理调用服务。开发者只能使用Http请求来进行请求,而使得客户端真正是语言无关的。

    Microsoft.Http.dll 和 Microsoft.Http.Extensions.dll,它们是微软提供的REST客户端包。可以更加方便地操作 HttpRequest/Response,你可以在这里下到: http://aspnet.codeplex.com/releases/view/24644 

    下载:WCF REST Starter Kit Preview 2.msi

    安装之后,在这里C:Program Files (x86)Microsoft WCF RESTWCF REST Starter Kit Preview 2Assemblies(默认安装的) 你可以找到相关的程序集

    代码片段

    查询:HttpClient.Get方法发送get请求,返回的是HttpResponseMessage,HttpResponseMessage.Content 返回的是你在服务端设置ResponseFormat = WebMessageFormat.Xml数据,当然也可以返回json数据。

    复制代码
                var client = new HttpClient();
                var strUrl = "http://localhost:21074/userInfo/api/users";
                var response = client.Get(strUrl);
                response.EnsureStatusIsSuccessful();
                var xml = response.Content.ReadAsString();
                Console.WriteLine(xml);
                Console.Read();
    复制代码

    添加数据,将数据序列化成Json格式放进 HttpContent 再使用 HttpClient.Post 提交 HttpContent 数据。
    HttpContent 需要指定 ContentType 是Json格式的。

    复制代码
                var client = new HttpClient();
                var strPostUrl = "http://localhost:21074/userInfo/api/users";
                var postData = new { ID = 5, Name = "zhang san", Gender = true, Birthday = DateTime.Now, Age = 23 };
                System.Web.Script.Serialization.JavaScriptSerializer jss = new JavaScriptSerializer();
                HttpContent content = HttpContent.Create(Encoding.UTF8.GetBytes(jss.Serialize(postData)),"application/json");
                HttpResponseMessage responseMessage = client.Post(strPostUrl, content);
                Console.WriteLine(responseMessage.EnsureStatusIsSuccessful().StatusCode);
    复制代码

    服务端

    客户端

    更新数据:找到id为1的用户信息,并修改。

    复制代码
                var client = new HttpClient();
                var strPostUrl = "http://localhost:21074/userInfo/api/users";
                var postData = new { ID = 1, Name = "zhang san", Gender = true, Birthday = DateTime.Now, Age = 22 };
                System.Web.Script.Serialization.JavaScriptSerializer jss = new JavaScriptSerializer();
                HttpContent content = HttpContent.Create(Encoding.UTF8.GetBytes(jss.Serialize(postData)), "application/json");
                HttpResponseMessage responseMessage = client.Put(strPostUrl, content);
                Console.WriteLine(responseMessage.EnsureStatusIsSuccessful().StatusCode);
    复制代码

    客户端

    删除数据:找到id为1的,删除它

                var client = new HttpClient();
                var strPostUrl = "http://localhost:21074/userInfo/api/users/{0}";
                HttpResponseMessage responseMessage = client.Delete(string.Format(strPostUrl,1));
                Console.WriteLine(responseMessage.EnsureStatusIsSuccessful().StatusCode);
                Console.Read();

    总结

    这里将restful的增删改查操作重新修改了下,需要注意的地方是,操作的处理是以Method方法而定,而不是url,post(增加),get(查询),delete(删除),put(更改),通过上面的例子你也会发现,请求的url相同,但是不同的请求谓词(post,get,delete,put)带来的操作并不相同。另外本文也介绍了客户但HttpClient的使用。

    参考文章:

    http://blog.csdn.net/fangxing80/article/details/6247297

    • 博客地址:http://www.cnblogs.com/wolf-sun/ 
      博客版权:如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步! 再次感谢您耐心的读完本篇文章。
  • 相关阅读:
    Python3 日期与时间戳相互转换
    PHP 二维数组排序保持键名不变
    C# Command命令(行为型模式)+队列 实现事务,带异步命令重试机制和生命周期
    领域驱动系列五模型驱动设计的构造块
    领域驱动系列四之模型驱动
    领域驱动系列三
    领域驱动系列二策略模式的应用
    领域驱动系列一基本概念介绍
    Redis学习系列七分布式锁
    Redis学习系列六ZSet(有序列表)及Redis数据结构的过期
  • 原文地址:https://www.cnblogs.com/Jeely/p/11062571.html
Copyright © 2020-2023  润新知