gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 22:40:02 25 4
gpt4 key购买 nike

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

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

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

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

提前致谢,
格雷格

编辑

在从事各种项目一段时间后,我发现了一种在 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。我喜欢包括整个类(class),以便新手可以看到所有内容,所以如果这对您的口味来说过于冗长,我很抱歉。


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 转换为对象。这是我修改的一个类。我很抱歉,因为我不记得原始来源。 (这门课可能还有很大的提升空间)

对象序列化器
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;
}

}
}
}

最后,您需要在 Controller 中使用您的存储库。我在这里没有使用任何依赖注入(inject) (DI),但您最好在最终构建中使用。

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

我是即时输入的,并根据我的实际解决方案对其进行了修改,因此对于任何拼写错误或错误,我深表歉意。我会尽我最大的努力纠正我发现的任何问题,但这应该为创建可重用的解决方案以处理基于 REST 的 Web 服务提供一个良好的开端。

最佳答案

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

这个类可以是静态的,但不一定是静态的——如果你有疑问,那就不要让它成为静态的。

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

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

关于asp.net-mvc - 在 .NET MVC 3 中使用 REST Web 服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4970542/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com