珂珂的个人博客 - 一个程序猿的个人网站

webapi的使用

    在asp.net mvc4中,微软带来一个新的东西Web Api,它只一种轻量化的REST风格服务,它比复杂的SOAP更加简洁,简单来说就是把事物分解成具体的资源,然后对资源进行增删改查,分别对应POST,DELETE,PUT,GET。当然我们也可以不依赖Web Api框架来实现自己的REST风格服务.

    下面说说Web Api具体用法及一些Demo和遇到的问题,新建一个web api项目,来写一个Article服务.

    public class ArticleController : ApiController
    {
        // GET api/        private IArticle articleDal = FYJ.Web.IocFactory.Instance;
        private IArticleView articleViewDal = FYJ.Web.IocFactory.Instance;
        public IComment CommentDal
        {
            get
            {
                return FYJ.Web.IocFactory.Instance;
            }
        }

        public IEnumerable Get()
        {
            GridPager pager = new GridPager();
            IEnumerable list = articleViewDal.GetList(ref pager, null).Select(c => new blog_view_article
            {
                articleID = c.articleID,
                siteCategoryDisplay = c.siteCategoryDisplay,
                categoryDisplay = c.categoryDisplay,
                topicDisplay = c.topicDisplay,
                ADD_DATE = c.ADD_DATE,
                articleAddUserID = c.articleAddUserID,
                articleAttachmentLimit = c.articleAttachmentLimit,
                articleAuthor = c.articleAuthor,
                articleTitle = c.articleTitle,
                articleSubContentText = c.articleSubContentText
            }).ToList();

            return list;
        }

        // GET api//5
        public blog_view_article Get(int id)
        {
            blog_view_article m = articleViewDal.GetEntities().Where(c => c.articleID == id).FirstOrDefault();

            return m;
        }

        //public HttpResponseMessage Get2(int id)
        //{
        //    blog_view_article m = articleViewDal.GetEntities().Where(c => c.articleID == id).FirstOrDefault();
        //    HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent("dddddd", Encoding.GetEncoding("UTF-8"), "application/json") };

        //    System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
        //    string json = serializer.Serialize(m);
        //    return result;
        //}

        // POST api/        //public void Post([FromBody]string value)
        //{

        //}

        public void Post([FromBody]blog_tb_article value)
        {

        }

        // PUT api//5
        public void Put(int id, [FromBody]blog_tb_article value)
        {
        }

        // DELETE api//5
        public void Delete(int id)
        {
        }
    }

这是修改后的ArticleController文件。 这里的Get、Put、Post、Delete方法不能重载,不然可能报错。

先说说Get方法,这里返回是一个IEnumerable对象,框架会将它序列化成json或者xml,当然你也可以定义自己的序列化。

默认情况下在ie中会输出json,在Chrome中可能会输出xml,这是因为请求的Accept不同造成的,我们让它全部返回json,只需要在Globl.asax.cs的 Application_Start方法中加入一句 GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();

Get方法序列化有一个问题,如果是用的EF返回那么必须把EF代理关闭掉db.Configuration.ProxyCreationEnabled = false; 否则默认的序列化器无法序列化. 

    再说说自定义序列化器,定义一个类继承自MediaTypeFormatter 这个类,然后重写一些方法,具体就不再研究了

 public class MyMediaTypeFormatter : MediaTypeFormatter
    {
        public override System.Threading.Tasks.Task WriteToStreamAsync(Type type, object value, System.IO.Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
        {
            return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
        }

        public override System.Threading.Tasks.Task WriteToStreamAsync(Type type, object value, System.IO.Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext, System.Threading.CancellationToken cancellationToken)
        {
            return base.WriteToStreamAsync(type, value, writeStream, content, transportContext, cancellationToken);
        }

        public override System.Threading.Tasks.Task ReadFromStreamAsync(Type type, System.IO.Stream readStream, System.Net.Http.HttpContent content, IFormatterLogger formatterLogger)
        {
            return base.ReadFromStreamAsync(type, readStream, content, formatterLogger);
        }

        public override System.Threading.Tasks.Task ReadFromStreamAsync(Type type, System.IO.Stream readStream, System.Net.Http.HttpContent content, IFormatterLogger formatterLogger, System.Threading.CancellationToken cancellationToken)
        {
            return base.ReadFromStreamAsync(type, readStream, content, formatterLogger, cancellationToken);
        }

        public override bool CanReadType(Type type)
        {
            return true;
        }

        public override bool CanWriteType(Type type)
        {
            return true;
        }
    }

然后再Globl.asax.cs的 Application_Start方法中加入

MyMediaTypeFormatter formatter = new MyMediaTypeFormatter();

GlobalConfiguration.Configuration.Formatters.Insert(0, formatter);

   下面说说Post方法,这个纠结了很久,默认是

 public void Post([FromBody]string value)

        {

        }

但是我在客户端Post的时候 这个value一直是null,将它参数改为对象

 public void Post([FromBody]blog_tb_article value)

        {


        }

然后客户端的时候加上 req.ContentType = "application/json";这样的话对象能取到

 Blogs.Entity.blog_tb_article model = new Blogs.Entity.blog_tb_article();
            model.articleTitle = "测试标题";
            System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            string json = serializer.Serialize(model);

            //System.Net.ServicePointManager.Expect100Continue = true;
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://service.ztku.com/api/Article/1102522");

            req.KeepAlive = true;
            req.Method = "Put";
            req.AllowAutoRedirect = true;
            req.ContentType = "application/json";
            req.Headers.Add("key", "11234");
            //req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            //req.Headers.Add("Accept-Encoding", "gzip,deflate");
            //req.Connection = "keep-alive";
            req.Timeout = 10000;


            byte[] postBytes = Encoding.UTF8.GetBytes(json); ;
            req.ContentLength = postBytes.Length;
            Stream st = req.GetRequestStream();
            st.Write(postBytes, 0, postBytes.Length);
            st.Close();


           HttpWebResponse res = (HttpWebResponse)req.GetResponse();

            Stream receiveStream = res.GetResponseStream();

            Encoding encode = Encoding.UTF8;
            if (res.CharacterSet != null && res.CharacterSet != "")
            {
                encode = Encoding.GetEncoding(res.CharacterSet);
            }

            StreamReader sr = new StreamReader(receiveStream, encode);
            string result = sr.ReadToEnd();
            sr.Close();

Put方法也与Post方法类似.

    在进行Put操作时,出现 远程服务器返回错误: (405) 不允许的方法,这个问题困扰了一上午,我的服务是挂在iis8.5上面,后来知道是因为装了一个WebDAV 的东西,在web.config配置中system.webServer 节点配置

 

     

   

runAllManagedModulesForAllRequests必须设为true


还有一个安全的问题需要考虑,服务端写一个类继承自DelegatingHandler 重写SendAsync方法

 protected override System.Threading.Tasks.Task SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {
            int matchHeaderCount = request.Headers.Count((item) =>
            {
                if ("key".Equals(item.Key))
                {
                    foreach (var str in item.Value)
                    {
                        if ("11234".Equals(str))
                        {
                            return true;
                        }
                    }
                }
                return false;
            });
            if (matchHeaderCount > 0)
            {
                return base.SendAsync(request, cancellationToken);
            }
            return Task.Factory.StartNew(() => { return new HttpResponseMessage(HttpStatusCode.Forbidden); });
        }

这个是需要客户端的request中传入一个header 

 HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://service.ztku.com/api/Article/1102522");

            req.KeepAlive = true;
            req.Method = "Put";
            req.AllowAutoRedirect = true;
            req.ContentType = "application/json";
            req.Headers.Add("key", "11234");

这里的验证方式就可以有多种了,我们可以给客户端分配一个密钥,用这个密钥来对称加密一个每次都变的随机字符串和url  服务端再解密.

   

还有个问题 如果系统中还有mvc的话 Global可能需要注意一个注册先后问题

  GlobalConfiguration.Configure(WebApiConfig.Register);

  RouteConfig.RegisterRoutes(RouteTable.Routes);

这里把api注册在前

当然webapi也可以脱离mvc使用的.


上一篇:wordpress3.6 修改的地方

下一篇:个人代码全部开源


0 评论

查看所有评论

给个评论吧