[c#] वेब एपीआई में धारावाहिक होने से संपत्ति को रोकें


Answers

[JsonIgnore] .NET वेब एपीआई में वेब एपीआई दस्तावेज पृष्ठ जेएसओएन और एक्सएमएल सीरियलाइजेशन के मुताबिक किसी संपत्ति पर सीरियलाइजेशन को स्पष्ट रूप से रोकने के लिए आप या तो एक्सएमएल [IgnoreDataMember] या [IgnoreDataMember] के लिए डिफ़ॉल्ट एक्सएमएल [JsonIgnore] लिए [JsonIgnore] उपयोग कर सकते हैं।

हालांकि परीक्षण में मैंने देखा है कि [IgnoreDataMember] एक्सएमएल और [IgnoreDataMember] दोनों अनुरोधों के लिए क्रमबद्धता को रोकता है, इसलिए मैं एकाधिक गुणों वाली संपत्ति को सजाने के बजाय इसका उपयोग करने की अनुशंसा करता हूं।

Question

मैं एक आराम एपीआई बनाने के लिए एक एमवीसी 4 वेब एपीआई और एएसपीनेट वेबफॉर्म 4.0 का उपयोग कर रहा हूं। यह बहुत अच्छा काम कर रहा है:

[HttpGet]
public HttpResponseMessage Me(string hash)
{
    HttpResponseMessage httpResponseMessage;
    List<Something> somethings = ...

    httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK, 
                                 new { result = true, somethings = somethings });

    return httpResponseMessage;
}

अब मुझे कुछ गुणों को क्रमबद्ध करने की आवश्यकता है। मुझे पता है कि मैं सूची में कुछ linq का उपयोग कर सकता हूं और केवल मुझे आवश्यक गुण प्राप्त कर सकता हूं, और सामान्यतः यह एक अच्छा दृष्टिकोण है, लेकिन वर्तमान परिदृश्य में something वस्तु बहुत जटिल है, और मुझे विभिन्न तरीकों से गुणों का एक अलग सेट चाहिए, इसलिए रन टाइम पर, प्रत्येक संपत्ति को अनदेखा करना आसान है।

क्या ऐसा करने के लिए कोई रास्ता है?




जो भी आप चाहते हैं उसे पूरा करने के लिए मैं आपको 2 तरीके दिखाऊंगा:

पहला तरीका: उस क्षेत्र के क्रमबद्धीकरण को छोड़ने के लिए जेसनप्रोपर्टी विशेषता के साथ अपने क्षेत्र को सजाने के लिए यदि यह शून्य है।

public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public List<Something> Somethings { get; set; }
}

दूसरा तरीका: यदि आप कुछ जटिल परिदृश्यों के साथ बातचीत कर रहे हैं तो आप कुछ विशिष्ट तर्क के आधार पर उस क्षेत्र के क्रमबद्धीकरण को छोड़ने के लिए वेब एपी कन्वेंशन ("कंधेरियलाइज") का उपयोग कर सकते हैं।

public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }

    public List<Something> Somethings { get; set; }

    public bool ShouldSerializeSomethings() {
         var resultOfSomeLogic = false;
         return resultOfSomeLogic; 
    }
}

WebApi JSON.Net का उपयोग करता है और यह क्रमिकरण के प्रति प्रतिबिंब का उपयोग करता है, इसलिए जब यह पता चला है (उदाहरण के लिए) ShouldSerializeFieldX () विधि फ़ील्डएक्स नाम वाले फ़ील्ड को क्रमबद्ध नहीं किया जाएगा।




यह मेरे लिए काम करता है: कस्टम कॉन्ट्रैक्ट रिज़ॉल्वर बनाएं जिसमें एक सार्वजनिक संपत्ति है जिसे स्ट्रिंग सरणी प्रकार की AllowList कहा जाता है। अपनी कार्रवाई में, कार्रवाई को वापस करने की आवश्यकता के आधार पर उस संपत्ति को संशोधित करें।

1. एक कस्टम अनुबंध संकल्पक बनाएँ:

public class PublicDomainJsonContractResolverOptIn : DefaultContractResolver
{
    public string[] AllowList { get; set; }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);

        properties = properties.Where(p => AllowList.Contains(p.PropertyName)).ToList();
        return properties;
    }
}

2. कार्रवाई में कस्टम अनुबंध रिज़ॉल्वर का उपयोग करें

[HttpGet]
public BinaryImage Single(int key)
{
    //limit properties that are sent on wire for this request specifically
    var contractResolver = Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver as PublicDomainJsonContractResolverOptIn;
    if (contractResolver != null)
        contractResolver.AllowList = new string[] { "Id", "Bytes", "MimeType", "Width", "Height" };

    BinaryImage image = new BinaryImage { Id = 1 };
    //etc. etc.
    return image;
}

इस दृष्टिकोण ने मुझे क्लास परिभाषा को संशोधित करने के बजाय विशिष्ट अनुरोध के लिए अनुमति / अनुमति देने की अनुमति दी। और यदि आपको XML App_Start\WebApiConfig.cs आवश्यकता नहीं है, तो इसे अपने App_Start\WebApiConfig.cs में बंद करना न भूलें या यदि आपका ग्राहक App_Start\WebApiConfig.cs बजाय xml अनुरोध करता है तो आपका एपीआई अवरुद्ध गुण वापस कर देगा।

//remove xml serialization
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);



लगभग greatbear302 के उत्तर के समान, लेकिन मैं प्रति अनुरोध अनुबंधResolver बनाते हैं।

1) एक कस्टम अनुबंध Resolver बनाएँ

public class MyJsonContractResolver : DefaultContractResolver
{
    public List<Tuple<string, string>> ExcludeProperties { get; set; }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);

        if (ExcludeProperties?.FirstOrDefault(
            s => s.Item2 == member.Name && s.Item1 == member.DeclaringType.Name) != null)
        {
            property.ShouldSerialize = instance => { return false; };
        }

        return property;
    }
}

2) कार्रवाई में कस्टम अनुबंध संकल्प का उपयोग करें

public async Task<IActionResult> Sites()
{
    var items = await db.Sites.GetManyAsync();

    return Json(items.ToList(), new JsonSerializerSettings
    {
        ContractResolver = new MyJsonContractResolver()
        {
            ExcludeProperties = new List<Tuple<string, string>>
            {
                Tuple.Create("Site", "Name"),
                Tuple.Create("<TypeName>", "<MemberName>"),
            }
        }
    });
}

संपादित करें:

यह अपेक्षित काम नहीं करता था (प्रति अनुरोध रिज़ॉलर अलग)। मैं अज्ञात वस्तुओं का उपयोग करूंगा।

public async Task<IActionResult> Sites()
{
    var items = await db.Sites.GetManyAsync();

    return Json(items.Select(s => new
    {
        s.ID,
        s.DisplayName,
        s.Url,
        UrlAlias = s.Url,
        NestedItems = s.NestedItems.Select(ni => new
        {
            ni.Name,
            ni.OrdeIndex,
            ni.Enabled,
        }),
    }));
}



किसी कारण से [IgnoreDataMember] हमेशा मेरे लिए काम नहीं करता है, और मुझे कभी-कभी Exception (या समान) मिलता है। तो इसके बजाय (या इसके अतिरिक्त) मैंने अपने एपीआई में Objects में POST करते समय इस तरह कुछ दिखने वाले पैटर्न का उपयोग करना शुरू कर दिया है:

[Route("api/myroute")]
[AcceptVerbs("POST")]
public IHttpActionResult PostMyObject(JObject myObject)
{
    MyObject myObjectConverted = myObject.ToObject<MyObject>();

    //Do some stuff with the object

    return Ok(myObjectConverted);
}

तो मूल रूप से मैं एक JObject में पास करता JObject और इसे अंतर्निहित सीरियलाइज़र के कारण होने वाली समस्याओं को दूर करने के बाद इसे परिवर्तित कर देता JObject जो कभी-कभी वस्तुओं को पार्स करते समय अनंत लूप का कारण बनता है।

अगर किसी को कोई कारण पता है कि यह किसी भी तरह से एक बुरा विचार है, तो कृपया मुझे बताएं।

यह ध्यान देने योग्य हो सकता है कि यह एक EntityFramework क्लास-प्रॉपर्टी के लिए निम्न कोड है जो समस्या का कारण बनता है (यदि दो वर्ग एक-दूसरे को संदर्भित करते हैं):

[Serializable]
public partial class MyObject
{
   [IgnoreDataMember]
   public MyOtherObject MyOtherObject => MyOtherObject.GetById(MyOtherObjectId);
}

[Serializable]
public partial class MyOtherObject
{
   [IgnoreDataMember]
   public List<MyObject> MyObjects => MyObject.GetByMyOtherObjectId(Id);
}





Related