在 .NET MVC 3 中使用 REST Web 服务

发布于 2024-10-16 18:03:33 字数 13171 浏览 11 评论 0原文

我正在开发 .NET 4 MVC 3 应用程序。我正在尝试遵循领域驱动的设计范例。现在,我的应用程序分为两部分:一个域和我的 Web MVC 代码。我需要一些帮助来确定我应该在这个结构中的哪个位置使用 RESTful Web 服务。

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

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

2.) 这个服务代码应该放在哪里?同样,我的直觉告诉我,除了代码的 Domain 和 WebUI 部分之外,我还需要第三个 Services 部分,其中包含这些 Web 服务客户端的接口和实现,但由于 Web 服务返回客户的 XML 表示形式和我域中的用户实体,服务不会真正与域分离。

提前致谢, Greg

编辑

在从事各种项目一段时间后,我发现了一种在 MVC 中处理 REST Web 服务的好方法。

首先,我创建代表我将使用的各种 Web 服务的实体。每个实体都使用 XML 属性来将属性与 XML 元素进行匹配。下面是一个假设的 Web 服务的简单示例,该服务返回有关人员及其衬衫的信息(这很愚蠢,但这是我能即时想到的最好的方法)。

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

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

然后我将有两个实体:Person 和 Shirt。我喜欢包含整个课程,以便新手可以看到所有内容,所以如果这对您来说太冗长,我很抱歉。

Person

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; }
    }
}

Shirt

    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, 0, 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 path, Dictionary<string, 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 服务的可重用解决方案提供一个良好的开端。

I am working on a .NET 4 MVC 3 application. I'm trying to follow a domain driven design paradigm. Right now, my application is broken into two pieces, a domain and my MVC code for the web. I'd like some help in determining where in this structure I should consume a RESTful web service.

This specific project uses a RESTful web service to retrieve and persist data. In my domain, I have two entities "Customer" and "User" which pair up with web services of the same name. e.g. URL/Customer and URL/User. Each web services takes a few parameters and then returns an appropriate list of data in XML. I need to implement basic CRUD functionality in the form of (POST, GET, PUT and DELETE). Given this, I have two main questions.

1.) What type of object should I create to consume these web services? My gut instinct is to create an ICustomerService interface that defines my CRUD operations, and then create an implementation of that interface in the form of a class that uses HTTPWebConnection (or extends it?). Is there a better way to consume RESTful web services? Should this type of class be static?

2.) Where should this service code go? Again, my gut tells me that in addition to the Domain and WebUI sections of my code, I need a third, Services section that contains the interfaces and implementations of these web service clients, but since the web services are returning XML representations of the Customer and User entities that are in my domain, the services won't really be de-coupled from the domain.

Thanks in advance,
Greg

EDIT

After working on various projects for some time, I've found a good way of handling REST web services in MVC.

Firstly, I create Entities that represent the various web services that I will be using. Each entity uses XML attributes to match up the properties with the XML elements. Here's a simple example for a hypothetical web service that returns information about people and their shirts (it's stupid, but the best I could come up with on the fly).

Let's say I'm getting a Person object from the web service. Here's the XML.

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

I would then have two entities: Person and Shirt. I like to include the entire class so that newbies can see everything, so I'm sorry if this is too verbose for your tastes.

Person

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; }
    }
}

Shirt

    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; }
        }

    }

We can then use a XmlSerializer to convert object to XML and XML to objects. Here is a class I modified to do this. I apologize as I don't remember the original source. (There is probably a lot of room for improvement within this class)

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);
    }
}

Then, create a generic service to handle your HTTP operations. I use GET and POST. Here is my class.

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, 0, 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 path, Dictionary<string, 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;
        }

    }
}

Then you create your repository to use the HttpService. I implemented an easy GetPeople() method that would return people from a web service query.

Repository

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;
            }

        }
    }
}

Finally, you need to use your repository in your controller. I'm not using any dependency injection here (DI), but you'd ideally want to in your final build.

Controller

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>();
        }
    }
}

I typed this up on the fly and modified it from my actual solution, so I apologize for any typos or errors. I'll do my best to correct anything that I find, but this should give a good start to creating a re-usable solution for dealing with REST-based web services.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一抹微笑 2024-10-23 18:03:33

你走在正确的轨道上。我会将 ICustomerService 放置在域包中,并将此服务的 HttpWebConnection 实现放置在引用域包的单独包中。

该类可以是静态的,但不一定是静态的 - 如果您有疑问,请不要将其设为静态。

您说得对,服务并未与域完全解耦,但这是因为它们根据域实现了域层中定义的服务契约。
与域分离的事实是它们是soap/webservice 客户端或http/rest 客户端,而这些是您不希望在域代码中出现的技术细节。

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

You're on the right track. I would place the ICustomerService in the domain package, and an HttpWebConnection implementation of this service in a separate package that references the domain package.

This class can be static, but does not have to be - if you're in doubt, then don't make it static.

You're right that the services are not completely decoupled from the domain, but that is because they implement a service contract defined in the domain layer, in terms of the domain.
What is decoupled from the domain is the fact that they're soap/webservice clients or http/rest clients and those are the technical details that you don't want in your domain code.

So your service implementation translates XML into domain entities and makes them available to the other objects in the domain.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文