微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

asp.net-mvc – 在.NET MVC 3中使用REST Web服务

我正在使用.NET 4 MVC 3应用程序.我试图遵循域驱动的设计范例.现在,我的应用程序分为两个部分,一个是域和我的MVC代码.我想要一些帮助来确定在这个结构中我应该使用一个RESTful Web服务.

该特定项目使用RESTful Web服务来检索和保留数据.在我的域中,我有两个实体“客户”和“用户”,与同名的Web服务配对.例如网址/客户和网址/用户.每个Web服务都需要一些参数,然后以XML格式返回适当的数据列表.我需要以(POST,GET,PUT和DELETE)的形式实现基本的CRUD功能.鉴于此,我有两个主要问题.

1.我应该创建什么类型的对象来使用这些Web服务?我的直觉是创建一个定义我的CRUD操作的ICustomerService接口,然后以使用HTTPWebConnection(或扩展它)的类的形式创建该接口的实现.有没有更好的方式来消费RESTful Web服务?这种类应该是静态的吗?

2.)这个服务代码应该在哪里?我的直觉告诉我,除了我的代码的Domain和WebUI部分,我需要第三个Services部分,其中包含这些Web服务客户端的接口和实现,但是由于Web服务返回客户的XML表示和我的域中的用户实体,服务将不会真正地从域中解除耦合.

提前致谢,
格雷格

编辑

在多个项目工作了一段时间之后,我发现了一种在MVC中处理REST Web服务的好方法.

首先,我创建代表我将要使用的各种Web服务的实体.每个实体使用XML属性来匹配XML元素的属性.这是一个简单的示例,用于返回有关人员和衬衫的信息(这是愚蠢的,但是我能够快速提出).

假设我从Web服务获取一个Person对象.这是XML.

<result>
    <resultCount>1</resultCount>
    <person>
        <personName>Tom</personName>
        <shirt>
            <shirtColor>red</shirtColor>
            <shirtType>sweater</shirtType>
        </shirt>
    </person>
</result>

我会有两个实体:人和衬衫.我喜欢包括整个班级,以便新手可以看到所有的东西,所以我很抱歉,如果这对你的口味来说太冗长了.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Serialization;

namespace Test.Entities
{
    [XmlRoot("person")]
    public class Person
    {
        /*
        Notice that the class name doesn't match the XML Element. This is okay because we
        are using XmlElement to tell the deserializer that 
        Name and <personName> are the same thing
        */
        [XmlElement("personName")]
        public string Name { get; set; }

        [XmlElement("shirt")]
        public Shirt Shirt { get; set; }
    }
}

衬衫

using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Xml.Serialization;

    namespace Test.Entities
    {
        public class Shirt
        {
            [XmlElement("shirtColor")]
            public string Color { get; set; }

            [XmlElement("shirtType")]
            public string Type { get; set; }

            /*
            This is specific to our Entity and doesn't exist in the web service so we can use
            XmlIgnore to make the deserializer ignore it
            */      
            [XmlIgnore]
            public string SpecialDbId { get; set; }
        }

    }

然后,我们可以使用XmlSerializer将对象转换为XML和XML到对象.这是我修改过的一个类.我很抱歉,因为我不记得原来的来源. (这个班级内可能还有很多改进的余地)

ObjectSerializer

using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using System;
using System.Xml.Linq;

public static class ObjectSerializer
{
    /// <summary>
    /// To convert a Byte Array of Unicode values (UTF-8 encoded) to a complete String.
    /// </summary>
    /// <param name="characters">Unicode Byte Array to be converted to String</param>
    /// <returns>String converted from Unicode Byte Array</returns>
    private static string UTF8ByteArrayToString(byte[] characters)
    {
        UTF8Encoding encoding = new UTF8Encoding();
        string constructedString = encoding.GetString(characters);
        return (constructedString);
    }

    /// <summary>
    /// Converts the String to UTF8 Byte array and is used in De serialization
    /// </summary>
    /// <param name="pXmlString"></param>
    /// <returns></returns>
    private static Byte[] StringToUTF8ByteArray(string pXmlString)
    {
        UTF8Encoding encoding = new UTF8Encoding();
        byte[] byteArray = encoding.GetBytes(pXmlString);
        return byteArray;
    }

    /// <summary>
    /// Serialize an object into an XML string
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static string SerializeObject<T>(T obj)
    {
        try
        {
            XDocument xml;
            using (MemoryStream stream = new MemoryStream())
            {
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("","");
                XmlSerializer serializer = new XmlSerializer(typeof(T));
                serializer.Serialize(stream,obj,ns);
                stream.Close();
                byte[] buffer = stream.ToArray();
                UTF8Encoding encoding = new UTF8Encoding();
                string stringXml = encoding.GetString(buffer);
                xml = XDocument.Parse(stringXml);
                xml.Declaration = null;
                return xml.ToString();
            }

        }
        catch
        {
            return string.Empty;
        }
    }

    /// <summary>
    /// Reconstruct an object from an XML string
    /// </summary>
    /// <param name="xml"></param>
    /// <returns></returns>
    public static T DeserializeObject<T>(string xml)
    {
        XmlSerializer xs = new XmlSerializer(typeof(T));
        MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(xml));
        XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream,Encoding.UTF8);
        return (T)xs.Deserialize(memoryStream);
    }
}

然后,创建一个通用服务来处理你的HTTP操作.我使用GET和POST.这是我的课

HttpService的

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Xml.Linq;

namespace Test.Infrastructure
{
    public class HttpService
    {
        public HttpService()
        {
            ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(AcceptCertificate);
        }

        public XDocument Post(Uri host,string path,Dictionary<string,string> headers,string payload,NetworkCredential credential)
        {
            try
            {
                Uri url = new Uri(host.Url,path);
                MvcHtmlString encodedPayload = MvcHtmlString.Create(payload);
                UTF8Encoding encoding = new UTF8Encoding();
                byte[] data = encoding.GetBytes(encodedPayload.ToHtmlString());

                HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
                request.Method = "POST";
                request.Credentials = credential;
                request.ContentLength = data.Length;
                request.KeepAlive = false;
                request.ContentType = "application/xml";

                MvcHtmlString htmlString1;
                MvcHtmlString htmlString2;
                foreach (keyvaluePair<string,string> header in headers)
                {
                    htmlString1 = MvcHtmlString.Create(header.Key);
                    htmlString2 = MvcHtmlString.Create(header.Value);
                    request.Headers.Add(htmlString1.ToHtmlString(),htmlString2.ToHtmlString());
                }

                using (Stream requestStream = request.GetRequestStream())
                {
                    requestStream.Write(data,data.Length);
                    requestStream.Close();
                }

                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                using (Stream responseStream = response.GetResponseStream())
                {
                    if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Created)
                    {
                        throw new HttpException((int)response.StatusCode,response.StatusDescription);
                    }

                    XDocument xmlDoc = XDocument.Load(responseStream);
                    responseStream.Close();
                    response.Close();

                    return xmlDoc;
                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        public XDocument Get(Uri host,string> parameters,NetworkCredential credential)
        {
            try
            {
                Uri url;
                StringBuilder parameterString = new StringBuilder();

                if (parameters == null || parameters.Count <= 0)
                {
                    parameterString.Clear();
                } else {
                    parameterString.Append("?");
                    foreach (keyvaluePair<string,string> parameter in parameters)
                    {
                        parameterString.Append(parameter.Key + "=" + parameter.Value + "&");
                    }
                }
                url = new Uri(host.Url,path + parameterString.ToString().TrimEnd(new char[] { '&' }));

                HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
                request.Credentials = credential;
                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        throw new HttpException((int)response.StatusCode,response.StatusDescription);
                    }

                    XDocument xmlDoc = XDocument.Load(response.GetResponseStream());
                    return xmlDoc;

                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }


        /*
        I use this class for internal web services.  For external web services,you'll want
        to put some logic in here to determine whether or not you should accept a certificate
        or not if the domain name in the cert doesn't match the url you are accessing.
        */
        private static bool AcceptCertificate(object sender,X509Certificate certificate,X509Chain chain,SslPolicyErrors errors)
        {
            return true;
        }

    }
}

然后创建您的存储库以使用HttpService.我实现了一个简单的GetPeople()方法,可以从Web服务查询返回人员.

知识库

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Linq;
using System.Configuration;
using Test.Entities;

namespace Test.Infrastructure
{
    public class PersonRepository
    {
        private HttpService _httpService;

        public PersonRepository()
        {
            _httpService = new HttpService();
        }

        public IQueryable<Person> GetPeople()
        {
            try
            {
                Uri host = new Uri("http://www.yourdomain.com");
                string path = "your/rest/path";
                Dictionary<string,string> parameters = new Dictionary<string,string>();

                //Best not to store this in your class
                NetworkCredential credential = new NetworkCredential("username","password");

                XDocument xml = _httpService.Get(host,path,parameters,credential);
                return ConvertPersonXmlToList(xml).AsQueryable();

            } 
            catch
            {
                throw;
            }
        }

        private List<Person> ConvertPersonXmlToList(XDocument xml)
        {
            try
            {
                List<Person> perople = new List<Person>();
                var query = xml.Descendants("Person")
                                .Select(node => node.ToString(SaveOptions.disableFormatting));
                foreach (var personXml in query)
                {
                    people.Add(ObjectSerializer.DeserializeObject<Person>(personXml));
                }
                return people;
            }
            catch
            {
                throw;
            }

        }
    }
}

最后,您需要在控制器中使用您的存储库.我没有在这里使用任何依赖注入(DI),但你最好要在最后的版本中.

调节器

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Test.Entities;
using Test.Infrastructure;
using System.Net;
using System.Text;

namespace Test.Controllers
{
    public class PeopleController
    {
        private PersonRepository _personRepository;

        public PeopleController()
        {
            _personRepository = new PersonRepository();
        }

        public List<Person> List()
        {
            return _personRepository.GetPeople().ToList<Person>();
        }
    }
}

我在飞行中输入了这个,并将其从我的实际解决方案中进行了修改,所以我为任何打字错误或者错误道歉.我会尽力纠正我发现的任何东西,但这应该是一个很好的开始,创建一个可用的解决方案来处理基于REST的Web服务.

解决方法

你在正确的轨道上我会将ICustomerService放在域包中,并在一个单独的包中引用该域包的HttpWebConnection实现该服务.

这个类可以是静态的,但不一定是 – 如果你有疑问,那么不要使它静态.

您是对的,服务不是完全从域解耦,而是因为它们实现了在领域层定义的服务契约.
与域分离的是它们是soap / webservice客户端或http / rest客户端,而这些是您不需要在域代码中的技术细节.

因此,您的服务实现将XML转换为域实体,并使其可用于域中的其他对象.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐