2013-06-10 9 views
5

मेरे पास एक एएसपी.नेट वेबएपी परियोजना है जिसका मैं काम कर रहा हूं। बॉस रिटर्न को "आंशिक प्रतिक्रिया" का समर्थन करने के लिए पसंद करेंगे, जिसका अर्थ है कि डेटा मॉडल में 50 फ़ील्ड हो सकते हैं, क्लाइंट प्रतिक्रिया के लिए विशिष्ट फ़ील्ड का अनुरोध करने में सक्षम होना चाहिए। इसका कारण यह है कि यदि वे उदाहरण के लिए एक सूची लागू कर रहे हैं तो उन्हें केवल 50 फ़ील्ड के ऊपरी हिस्से की आवश्यकता नहीं है, वे शायद सूची बनाने के लिए पहला नाम, अंतिम नाम और आईडी चाहते हैं। इस प्रकार मैंने एक कस्टम कॉन्ट्रैक्ट रिजॉल्वर (डायनेमिक कंट्रैक्ट रिसेल्वर) का उपयोग करके एक समाधान लागू किया है, जैसे कि जब कोई अनुरोध आता है तो मैं ऑनएक्शन एक्सेलिंग विधि में फ़िल्टर (फील्डलिस्ट फिल्टर) के माध्यम से इसमें देख रहा हूं और यह निर्धारित कर रहा हूं कि "फ़ील्डलिस्ट" नामक फ़ील्ड मौजूद है या नहीं और तो अगर यह है कि मैं अपने डायनामिक कंट्रैक्ट रिसेल्वर के एक नए उदाहरण के साथ वर्तमान अनुबंध रिसेल्वर को बदल रहा हूं और मैं कन्स्ट्रक्टर को फ़ील्डलिस्ट पास करता हूं।एएसपी.नेट वेबएपी और आंशिक प्रतिक्रिया

कुछ नमूना कोड

DynamicContractResolver.cs

protected override IList<JsonProperty> CreateProperties(Type type, Newtonsoft.Json.MemberSerialization memberSerialization) 
    { 
     List<String> fieldList = ConvertFieldStringToList(); 

     IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization); 
     if (fieldList.Count == 0) 
     { 
      return properties; 
     } 
     // If we have fields, check that FieldList is one of them. 
     if (!fieldList.Contains("FieldList")) 
      // If not then add it, FieldList must ALWAYS be a part of any non null field list. 
      fieldList.Add("FieldList"); 
     if (!fieldList.Contains("Data")) 
      fieldList.Add("Data"); 
     if (!fieldList.Contains("FilterText")) 
      fieldList.Add("FilterText"); 
     if (!fieldList.Contains("PageNumber")) 
      fieldList.Add("PageNumber"); 
     if (!fieldList.Contains("RecordsReturned")) 
      fieldList.Add("RecordsReturned"); 
     if (!fieldList.Contains("RecordsFound")) 
      fieldList.Add("RecordsFound"); 
     for (int ctr = properties.Count-1; ctr >= 0; ctr--) 
     { 
      foreach (string field in fieldList) 
      { 
       if (field.Trim() == properties[ctr].PropertyName) 
       { 
        goto Found; 
       } 
      } 
      System.Diagnostics.Debug.WriteLine("Remove Property at Index " + ctr + " Named: " + properties[ctr].PropertyName); 
      properties.RemoveAt(ctr); 
     // Exit point for the inner foreach. Nothing to do here. 
     Found: { } 
     } 
     return properties; 
    } 

FieldListFilter.cs

public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) 
    { 
     if (!actionContext.ModelState.IsValid) 
     { 
      throw new HttpResponseException(HttpStatusCode.BadRequest); 
     } 
     // We need to determine if there is a FieldList property of the model that is being used. 
     // First get a reference to the model. 
     var modelObject = actionContext.ActionArguments.FirstOrDefault().Value; 
     string fieldList = string.Empty; 
     try 
     { 
      // Using reflection, attempt to get the value of the FieldList property 
      var fieldListTemp = modelObject.GetType().GetProperty("FieldList").GetValue(modelObject); 
      // If it is null then use an empty string 
      if (fieldListTemp != null) 
      { 
       fieldList = fieldListTemp.ToString(); 
      } 
     } 
     catch (Exception) 
     { 
      fieldList = string.Empty; 
     } 

     // Update the global ContractResolver with the fieldList value but for efficiency only do it if they are not the same as the current ContractResolver. 
     if (((DynamicContractResolver)GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver).FieldList != fieldList) 
     { 
      GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new DynamicContractResolver(fieldList); 
     } 
    } 

मैं तो json सामग्री पेलोड जैसे देख के साथ एक अनुरोध भेज सकते हैं:

{ 
    "FieldList":"NameFirst,NameLast,Id", 
    "Data":[ 
    { 
     "Id":1234 
    }, 
    { 
     "Id":1235 
    } 
    ] 
} 

और मैं बहुत ऐसी ही प्रतिक्रिया प्राप्त होगा:

{ 
    "FieldList":"NameFirst,NameLast,Id", 
    "Data":[ 
    { 
     "NameFirst":"Brian", 
     "NameLast":"Mueller", 
     "Id":1234 
    }, 
    { 
     "NameFirst":"Brian", 
     "NameLast":"Mueller", 
     "Id":1235 
    } 
    ] 
} 

मुझे विश्वास है कि ContractResolver का उपयोग कर सूत्रण समस्या आने पर हो सकता है। यदि मैं इसे एक अनुरोध के लिए बदलता हूं तो यह तब तक सभी अनुरोधों के लिए मान्य होगा जब तक कि कोई इसे किसी अन्य अनुरोध पर नहीं बदलता (परीक्षण के माध्यम से ऐसा लगता है) यदि ऐसा है, तो मुझे अपने उद्देश्य के लिए उपयोगिता दिखाई नहीं दे रही है।

संक्षेप में, मैं गतिशील डेटा मॉडल रखने का एक तरीका ढूंढ रहा हूं जैसे कि अनुरोध से आउटपुट अनुरोध के आधार पर ग्राहक द्वारा कॉन्फ़िगर करने योग्य है। Google इसे अपने वेब एपीआई में लागू करता है और वे इसे "आंशिक प्रतिक्रिया" कहते हैं और यह बहुत अच्छा काम करता है। मेरा कार्यान्वयन एक बिंदु पर काम करता है लेकिन मुझे डर है कि यह एकाधिक एक साथ अनुरोधों के लिए टूटा जाएगा।

सुझाव? युक्तियाँ?

+0

बस FYI ... जेसन फॉर्मेटर के लिए '$ select' सुविधा समर्थन की जांच करें जो अगली रिलीज में आ रहा है: https://aspnetwebstack.codeplex.com/wikipage?title=%24select%20and%20%24expand%20support&referringTitle = चश्मा –

+0

मुझे नहीं लगता कि मेरे पास अगले संस्करण की प्रतीक्षा करने का समय है। हमारे पास 2 महीने से भी कम समय में एक डेमो है और मुझे लागू करने के लिए बहुत कुछ मिला है। बिंदु पर और, मेरी विधि मूल रूप से टूटा हुआ है। मैंने वेब के सुझावों और ट्यूटोरियल्स के आधार पर कार्यान्वित किया था, लेकिन मेरे पास इसकी नींव के बारे में कुछ सवाल हैं जो मैं पूरी तरह समझ नहीं पा रहा हूं। –

+0

यदि आप प्रत्येक अनुरोध पर 'डायनामिक कंट्रैक्ट रिसेल्वर' का एक नया उदाहरण बनाते हैं और इसे 'कॉन्ट्रैक्ट रिसेल्वर' के रूप में उपयोग करते हैं, तो वहां एक सहमति समस्या नहीं होनी चाहिए। – muratgu

उत्तर

5

एक आसान समाधान जो काम कर सकता है।

सभी 50 सदस्यों के साथ एक मॉडल वर्ग बनाएं जो शून्य प्रकारों के साथ है। अनुरोधित सदस्यों को मान असाइन करें। परिणाम को सामान्य तरीके से वापस करें।

आपके WebApiConfig.Register() में आपको शून्य मान हैंडलिंग सेट करना होगा।

config.Formatters.JsonFormatter.SerializerSettings = 
     new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }; 
+0

अब यह एक दिलचस्प विकल्प की तरह लगता है जिसे मैंने नहीं माना था। मैं इसे तुरंत देख लूंगा क्योंकि मैं सहमत हूं कि यह कुछ प्रक्रिया को सरल बना देगा और तर्क को एपीआई की डेटा अनुवाद परत में ले जाएगा जहां मैं अधिक नियंत्रण रख सकता हूं। –

+0

मैंने इस समाधान को लागू किया और मेरे डायनेमिक कंट्रैक्ट रीसोलवर से दूर कर दिया। ऐसा लगता है कि यह बहुत अच्छी तरह से काम कर रहा है और इसमें अधिक पठनीय, अधिक समझने योग्य और मुझे "आवश्यक वापसी फ़ील्ड" जैसी चीजों के लिए कुछ अतिरिक्त लचीलापन देने का अतिरिक्त बोनस दिया गया है। सहायता के लिए धन्यवाद। –

+0

config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; – codebased

1

आपको कॉन्फ़िगरेशन को स्पर्श नहीं करना चाहिए। आपको प्रति-अनुरोध के आधार पर अनुबंध समाधानकर्ता की आवश्यकता है। आप इसे इस तरह की अपनी क्रिया विधि में उपयोग कर सकते हैं।

public class MyController : ApiController 
{ 
    public HttpResponseMessage Get() 
    { 
     var formatter = new JsonMediaTypeFormatter(); 
     formatter.SerializerSettings.ContractResolver = 
       new DynamicContractResolver(new List<string>() 
         {"Id", "LastName"}); // you will get this from your filter 

     var dto = new MyDto() 
       { FirstName = "Captain", LastName = "Cool", Id = 8 }; 

     return new HttpResponseMessage() 
     { 
      Content = new ObjectContent<MyDto>(dto, formatter) 
     }; 
     // What goes out is {"LastName":"Cool","Id":8} 
    } 
} 

ऐसा करने से, आप प्रतिक्रिया संदेशों के लिए JSON सामग्री प्रकार में अपने आप को ताला लगा रहे हैं, लेकिन आप पहले से ही एक Json.NET विशिष्ट सुविधा का उपयोग करके कि फैसला किया है। साथ ही, ध्यान दें कि आप एक नया JsonMediaTypeFormatter बना रहे हैं। इसलिए, कॉन्फ़िगरेशन में किसी को कॉन्फ़िगर करने के लिए जो कुछ भी मीडिया प्रकार मैपिंग इस दृष्टिकोण के साथ उपलब्ध नहीं होगा।

+0

बदरी, यह सच नहीं है कि वैश्विक विन्यास को छूकर मैं खुद को जेसन में लॉक कर रहा हूं। मैंने अनुरोध हेडर स्वीकार करके इसे पहले से ही परीक्षण कर लिया है: एप्लिकेशन/एक्सएमएल और यह कॉन्ट्रैक्टसेल्वर की परवाह किए बिना एक्सएमएल लौटाता है क्योंकि यह रिटर्न पथ पर बाईपास होता है और यह एक्सएमएल रिज़ॉल्वर का उपयोग करता है। मैं खुद को जेसन में लॉक नहीं करना चाहता हूं, यह परियोजना की एक आवश्यकता है कि अंतिम उपयोगकर्ता अनुरोध पर जेसन या एक्सएमएल वापस पाने में सक्षम हो। बॉस आंशिक सामग्री के बारे में चिंतित नहीं है अगर वे एक्सएमएल चुनते हैं, इसलिए मैं इस बिंदु पर प्रक्रिया के उस पक्ष से चिंतित नहीं हूं। –

0

मैं जानता हूँ कि इस सवाल का पहले कई वर्षों से है, लेकिन आप ढांचे के आधुनिक रिलीज के साथ यह करने के लिए देख रहे हैं, मैं आजकल OData सेवाओं का उपयोग करने (http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/using-select-expand-and-value) की सलाह देते हैं।

संबंधित मुद्दे