ServiceStack支持在每次调用的基础上有条件地忽略REST响应中的字段
至少,我正在寻找一种方法来有条件地排除资源上的某些属性,使其不被包含在每个呼叫的响应中(参见下面的fields
)。
理想情况下,我想使用ServiceStack实现REST服务,该服务支持以下所有要点。
UPDATE
虽然我一般都非常喜欢ServiceStack的方法,但如果可能的话,我更愿意使用它,如果它不是特别适合这些想法,我宁可不要向后弯腰,让它变得有效。 如果是这样的话,任何人都可以指向另一个可能更合适的c#框架吗? 当然,我正在积极探索其他选择。
在本次题为“ 设计REST + JSON API ”的演讲中,演示者在JSON中描述了他的资源引用策略(通过资源上的href
属性)。 除此之外,他还描述了两个查询参数( fields
和expand
),用于控制调用REST服务的响应所包含的数据。 我一直在努力尝试挖掘ServiceStack框架以获得对fields
支持,但迄今为止一直没有成功。 这在ServiceStack目前是否可行? 理想情况下,解决方案将与格式无关,因此可以使用所有ServiceStack支持的输出格式。 我认为expand
将采用相同的策略。
我将在这里描述这些function,但我认为链接上的谈话可以更好地解释它们。
假设我们有一个Profiles资源,其中包含以下属性: givenName
, surname
, gender
和favColor
。 “个人档案”资源还包括用户在socialNetworks
属性中所属的社交网络列表。
href
– (video中的42:22)每个资源都包含REST服务上的完整链接。 将返回对GET /profiles/123
调用
{ "href":"https://host/profiles/123", "givenName":"Bob", "surname":"Smith", "gender":"male", "favColor":"red", "socialNetworks": { "href":"https://host/socialNetworkMemberships?profileId=123" } }
请注意, socialNetworks
属性返回的对象仅填充了href值。 这样可以使响应更短且更集中,同时还为最终用户提供足够的信息,以便在需要时提供进一步的请求 在这个庄园中全面使用的href
属性使得重用资源数据结构作为其他资源的子项变得容易(概念上无论如何)。
fields
– (video中55:44)查询字符串参数,指示服务器仅在REST响应中包含所需资源的指定属性。
GET /profiles/123
正常响应将包括资源的所有属性,如上所示。 当fields
查询参数包含在请求中时,仅返回指定的字段。 ‘GET / propfiles / 123?fields = surname,favColor’会返回
{ "href":"https://host/profiles/123", "surname":"Smith", "favColor":"red" }
expand
– (video中的45:53)查询字符串参数,指示服务器充实结果中的指定子资源。 使用我们的示例,如果您要调用GET /profiles/123?expand=socialNetworks
您可能会收到类似的内容
{ "href":"https://host/profiles/123", "givenName":"Bob", "surname":"Smith", "gender":"male", "favColor":"red", "socialNetworks": { "href":"https://host/socialNetworkMemberships?profileId=123", "items": [ { "href":"https://host/socialNetworkMemberships/abcde", "siteName":"Facebook", "profileUrl":"https://www.facebook.com/..." }, ... ] } }
所以…在我看来,ServiceStack的最大特点是它使得通过HTTP发送,接收和处理POCO非常容易。 您如何设置POCO以及您之间(在“服务”中)之间的操作取决于您。 SS有意见吗? 是。 你必须同意他们吗? 不。(但你可能应该:))
我认为扩展下面这样的东西会让你接近你想要处理api的方式。 可能不是ServiceStack的最佳示例,但ServiceStack代码/要求几乎不会引起注意,并且不会妨碍您(AppHost配置未显示)。 您可以在其他.NET框架(MVC / Web API /等)中执行类似的操作,但在我看来,它看起来不像使用ServiceStack那样直接的C#/ .NET代码。
请求课程
[Route("/Profiles/{Id}")] public class Profiles { public int? Id { get; set; } } [Route("/SocialNetworks/{Id}")] public class SocialNetworks { public int? Id { get; set; } }
基本响应类
public class BaseResponse { protected virtual string hrefPath { get { return ""; } } public string Id { get; set; } public string href { get { return hrefPath + Id; } } }
来自示例的类
public class Profile : BaseResponse { protected override string hrefPath { get { return "https://host/profiles/"; } } public string GivenName { get; set; } public string SurName { get; set; } public string Gender { get; set; } public string FavColor { get; set; } public List SocialNetworks { get; set; } } public class SocialNetwork: BaseResponse { protected override string hrefPath { get { return "https://host/socialNetworkMemberships?profileId="; }} public string SiteName { get; set; } public string ProfileUrl { get; set; } }
服务
public class ProfileService : Service { public object Get(Profiles request) { var testProfile = new Profile { Id= "123", GivenName = "Bob", SurName = "Smith", Gender = "Male", FavColor = "Red", SocialNetworks = new List { new SocialNetwork { Id = "abcde", SiteName = "Facebook", ProfileUrl = "https://www.facebook.com/"} } }; if (!String.IsNullOrEmpty(this.Request.QueryString.Get("fields")) || !String.IsNullOrEmpty(this.Request.QueryString.Get("expand"))) return ServiceHelper.BuildResponseObject(testProfile, this.Request.QueryString); return testProfile; } } public class SocialNetworkService : Service { public object Get(SocialNetworks request) { var testSocialNetwork = new SocialNetwork { Id = "abcde", SiteName = "Facebook", ProfileUrl = "https://www.facebook.com/" }; if (!String.IsNullOrEmpty(this.Request.QueryString.Get("fields")) || !String.IsNullOrEmpty(this.Request.QueryString.Get("expand"))) return ServiceHelper.BuildResponseObject(testSocialNetwork, this.Request.QueryString); return testSocialNetwork; } }
反思助手class
public static class ServiceHelper { public static object BuildResponseObject(T typedObject, NameValueCollection queryString) where T: BaseResponse { var newObject = new ExpandoObject() as IDictionary; newObject.Add("href", typedObject.href); if (!String.IsNullOrEmpty(queryString.Get("fields"))) { foreach (var propertyName in queryString.Get("fields").Split(',').ToList()) { //could check for 'socialNetwork' and exclude if you wanted newObject.Add(propertyName, typedObject.GetType().GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).GetValue(typedObject, null)); } } if (!String.IsNullOrEmpty(queryString.Get("expand"))) { foreach (var propertyName in queryString.Get("expand").Split(',').ToList()) { newObject.Add(propertyName, typedObject.GetType().GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).GetValue(typedObject, null)); } } return newObject; } }
通常,您可以通过设置DataMember属性来控制DTO的序列化。 使用这些属性,您可以控制属性是否应具有默认值。 这意味着如果您只是不定义要返回的对象的属性,则不应该序列化它,因此不会在生成的Json中显示。
ServiceStack内部使用标准DataContract … Serializer,因此应该支持此function
否则,您也可以使用动态对象,只需在运行时编写对象,对其进行序列化并将其发回。 这是一个非常基本的例子:
上述就是C#学习教程:ServiceStack支持在每次调用的基础上有条件地忽略REST响应中的字段分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
var seri = JsonSerializer.Create(new JsonSerializerSettings() { }); using (var textWriter = new StringWriter()) { var writer = new JsonTextWriter(textWriter); dynamic item = new { Id = id }; seri.Serialize(writer, item); return textWriter.ToString(); }
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1026309.html