ওয়েব এপিআইতে সম্পত্তি ক্রমিকায়িত হতে বাধা দিন


174

আমি একটি এমভিসি 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;
}

এখন আমার কিছু বৈশিষ্ট্য সিরিয়ালায়িত হতে আটকাতে হবে। আমি জানি আমি তালিকার উপরে কিছু লিনকিউ ব্যবহার করতে পারি এবং কেবল আমার প্রয়োজনীয় বৈশিষ্ট্যগুলি পেতে পারি, এবং সাধারণত এটি একটি ভাল পদ্ধতির, তবে বর্তমান পরিস্থিতিতে somethingবস্তুটি খুব জটিল, এবং বিভিন্ন পদ্ধতিতে আমার আলাদা আলাদা বৈশিষ্ট্যের প্রয়োজন রয়েছে, তাই এটি চিহ্নিত করা সহজ, রানটাইম সময়ে, প্রতিটি সম্পত্তি উপেক্ষা করা হবে।

এটা করার কোন উপায় আছে?


আপনি সম্পত্তিটিতে স্ক্রিপ্টইগনোর যুক্ত করতে পারেন। এই প্রশ্ন দেখার stackoverflow.com/questions/10169648/...
atbebtg

উত্তর:


232

এএসপি.নেট ওয়েব এপিআইএল Json.Netডিফল্ট ফর্ম্যাটর হিসাবে ব্যবহার করে , সুতরাং যদি আপনার অ্যাপ্লিকেশনটি কেবলমাত্র JSON কে ডেটা ফর্ম্যাট হিসাবে ব্যবহার করে, আপনি [JsonIgnore]সিরিয়ালাইজেশনের জন্য সম্পত্তি উপেক্ষা করতে ব্যবহার করতে পারেন :

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

    [JsonIgnore]
    public List<Something> Somethings { get; set; }
}

তবে, এই উপায়টি এক্সএমএল ফর্ম্যাটকে সমর্থন করে না। সুতরাং, যদি আপনার অ্যাপ্লিকেশনটিকে আরও বেশি এক্সএমএল ফর্ম্যাটটিকে সমর্থন করতে হয় (বা কেবল এক্সএমএল সমর্থন করে), পরিবর্তে Json.Netআপনার ব্যবহার করা উচিত [DataContract]যা জেএসওএন এবং এক্সএমএল উভয় সমর্থন করে:

[DataContract]
public class Foo
{
    [DataMember]
    public int Id { get; set; }
    [DataMember]
    public string Name { get; set; }

    //Ignore by default
    public List<Something> Somethings { get; set; }
}

আরও বোঝার জন্য, আপনি অফিসিয়াল নিবন্ধটি পড়তে পারেন ।


আমি মনে করি jsonignore ব্যবহার করে রান সময় আমাকে অ্যাট্রিবিউট যুক্ত করতে এবং মুছে ফেলার কোনও উপায় খুঁজে বের করতে হবে।
ব্যবহারকারী 1330271

একটি স্বাদ মতো কাজ করেছেন! ধন্যবাদ :)
পাওলো রডরিগস

কেন এটি দুঃখের বিষয় যে জসনআইগনর বৈশিষ্ট্যটি এক্সএমএল প্রতিক্রিয়া সমর্থন করে না?
মুকুস

ডেটা কনট্র্যাক্ট একটি দুর্দান্ত সমাধান। এটি আমাকে একটি পরিষ্কার REST এপিআই দেয়। একই সময়ে যখন আমি কোনও সংখ্যা-স্কুলে ডেটা সংরক্ষণ করি তখন অবহেলিত বৈশিষ্ট্যগুলি জসন হিসাবে সংরক্ষণ করা সত্ত্বেও অব্যাহত বৈশিষ্ট্যগুলি বজায় থাকে।
ফ্র্যাঙ্কিহলিউড

1
@ ফেডারস্টিমন জসনআইগনোরের নেমস্পেসটি নিউটনসফট। জসন, জেএসওএন.নেট-নুগেট প্যাকেজ দরকার। DataContract এবং DataMember (যদি এটি অনুপস্থিত এবং রেফারেন্স) অন্যদিকে প্রয়োজন System.Runtime.Serialization-নামস্থান উপর -attributes
Esko

113

জাসন সিরিয়ালাইজারের জন্য বা ডিফল্ট এক্সএমএল সিরিয়ালাইজারের জন্য আপনি যে কোনও সম্পত্তি ব্যবহার করতে পারেন তা স্পষ্টরূপে এমন কোনও সম্পত্তিতে সিরিয়ালাইজেশন প্রতিরোধ করতে এএসপি.নেট ওয়েব এপিআই- তে [JsonIgnore]ওয়েবএসআই ডকুমেন্টেশন পৃষ্ঠা জাসন [IgnoreDataMember]এবং এক্সএমএল সিরিয়ালাইজেশন অনুসারে।

তবে পরীক্ষায় আমি লক্ষ করেছি যে [IgnoreDataMember]এক্সএমএল এবং জসন উভয়ের অনুরোধের জন্য সিরিয়ালকরণ রোধ করে, তাই আমি একাধিক বৈশিষ্ট্যযুক্ত কোনও সম্পত্তি সাজাবার চেয়ে এটি ব্যবহার করার পরামর্শ দেব।


2
এটি আরও ভাল উত্তর। এটি XML এবং JSON কে একটি বৈশিষ্ট্যের সাথে কভার করে।
অলিভার

17
দুঃখজনকভাবে [IgnoreDataMember]অলস-বোঝা ইএফ 6 প্রক্সি অবজেক্ট (ভার্চুয়াল বৈশিষ্ট্য) নিয়ে কাজ করতে দেখা যায় না। [DataContract]এবং [DataMember]যাইহোক, না।
নিক

32

সমস্ত কিছু ডিফল্টরূপে সিরিয়ালায়িত করার পরিবর্তে আপনি "অপ্ট-ইন" পদ্ধতিটি নিতে পারেন। এই দৃশ্যে, কেবলমাত্র আপনার নির্দিষ্ট করা বৈশিষ্ট্যগুলি ক্রমিকায়িত হওয়ার অনুমতি রয়েছে। আপনি সঙ্গে এই কাজ DataContractAttributeএবং DataMemberAttribute, পাওয়া System.Runtime.Serialization নামস্থান।

DataContactAttributeবর্গ প্রয়োগ করা হয়, এবং DataMemberAttributeপ্রতিটি সদস্য আপনি ধারাবাহিকভাবে করতে চান প্রয়োগ করা হয়:

[DataContract]
public class MyClass {

  [DataMember]
  public int Id { get; set;} // Serialized

  [DataMember]
  public string Name { get; set; } // Serialized

  public string DontExposeMe { get; set; } // Will not be serialized
}

সাহস আমি বলি এটি একটি আরও ভাল পদ্ধতির কারণ এটি আপনাকে সিরিয়ালাইজেশনের মাধ্যমে কী করবে বা কী করবে না সে সম্পর্কে সুস্পষ্ট সিদ্ধান্ত নিতে বাধ্য করে। এটি আপনার মডেল ক্লাসগুলিকে JSON.net এর উপর নির্ভরতা না নিয়ে নিজেরাই কোনও প্রকল্পে বাস করার অনুমতি দেয় কারণ আপনি অন্য কোথাও জেএসএন.নেটের মাধ্যমে সিরিয়ালকরণ করছেন।


2
উত্তরাধিকারী সদস্যদের আড়াল করার জন্য নেট কোর দিয়ে বাক্সটির বাইরে কাজ করার একমাত্র পন্থা। এক্সএমএল এবং জসন সিরিয়ালাইজেশন উভয়ের জন্য কাজ করে। যশ
Piou

আমার একই ফানসিওনিয়ালিটি দরকার তবে বৈশিষ্ট্যগুলি অন্তর্ভুক্ত বা বাদ দেওয়া হয় তার উপর নির্ভর করে যে এপিআই পদ্ধতিটি চাওয়া হয়েছে অর্থাৎ বিভিন্ন এপিআই কলগুলির জন্য বিভিন্ন ডেটা প্রয়োজন needed কোনও পরামর্শ
নিতিন চন্দ্রন

এটি দুর্দান্ত কাজ করে, তবে আমার মূল সমস্যাটি হ'ল এই কনফিগারেশনগুলি EF কোরের প্রতিটি dbcontext স্ক্যাফোল্ডের সাথে চলে যায়, কারও কি এর জন্য কোনও কার্যনির্বাহী কাজ রয়েছে? এই বৈশিষ্ট্যগুলি কোনও আংশিক শ্রেণিতে থাকতে পারে, বা প্রোগ্রামগতভাবে সেট করা যেতে পারে?
ন্যানের

20

এটি আমার জন্য কাজ করেছে: একটি কাস্টম কন্ট্রাক্ট রিসলভার তৈরি করুন যার স্ট্রিং অ্যারে প্রকারের 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;
    }
}

২. কাস্টম কন্ট্রাক্ট রিসলভারটি অ্যাকশনে ব্যবহার করুন

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

এই পদ্ধতির ফলে শ্রেণীর সংজ্ঞা পরিবর্তনের পরিবর্তে নির্দিষ্ট অনুরোধের জন্য আমাকে অনুমতি / বঞ্চিত করার অনুমতি দেওয়া হয়েছিল। এবং যদি আপনার এক্সএমএল সিরিয়ালাইজেশন প্রয়োজন না হয় তবে এটিকে বন্ধ করতে ভুলবেন না আপনার App_Start\WebApiConfig.csক্লায়েন্টটি যদি জসনের পরিবর্তে এক্সএমএল অনুরোধ করে তবে আপনার এপিআই ব্লক করা বৈশিষ্ট্যগুলি ফিরিয়ে দেবে।

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

নতুন সংস্করণগুলির সাথে অবশ্যই কিছু পরিবর্তন হয়েছে তবে আমি এটি কাজ করতে পারিনি। রেজোলভারটি সংশোধন করার সময় আমি 'হিসাবে' পরিবর্তে 'নতুন' করে কাজ করতে পারি। জসনকন্ট্র্যাক্ট রিসলবার টাইপ কোনও কারণে তুলনামূলক নয়। নতুন করার সমস্যাটি হ'ল এটি এটি কেবল একটির পরিবর্তে সকলের জন্য ওভাররাইট করে।
ক্যালেল ওয়েড

আমি অনুরোধ.ক্রেইটআরসিপোনস () পদ্ধতিটি ব্যবহার করি যা মিডিয়াটাইপ ফর্ম্যাটটারটি ব্যবহার করে এই কাজটি পরিচালনা করতে সক্ষম হয়েছি: var jsonMediaType Formatter = নতুন জসনমিডিয়া টাইপফর্মেটর {সিরিয়ালাইজারসেটেটিংস = নতুন জসনসিরাইজারসেটেটিংস {কন্ট্রাক্ট রিসোলভার = নতুন "কন্ট্রাক্টআরসিভারআলিংআর" বাইটস "," মাইমটাইপ "," প্রস্থ "," উচ্চতা "}}}}; অনুরোধ.ক্রেটআরস্পোনস (এইচটিপিস্ট্যাটাসকোড.ওকে, চিত্র, জসনমিডিয়াটাইপফর্ম্যাটর);
পল

যদি আমরাও চাই যে এক্সএমএল প্রতিক্রিয়াতে অবরুদ্ধ বৈশিষ্ট্যগুলি উপেক্ষা করা হয়?
কার্লোস পি

অনুরোধ অনুযায়ী একবারে ডেটা চুক্তির সমাধানকারীকে বরাদ্দ করা না হলে এটি থ্রেড নিরাপদ নয়। আমি মনে করি এটি একবার স্টার্টআপ ক্লাসে অর্পণ করা হয়েছে।
স্প্রেগ

2
আরও খারাপ, ive এটি পরীক্ষা করেছে এবং ক্রেডিট রেজলভার দ্বারা ক্রিয়েটপ্রোপার্টি কলকে ক্যাশে করা হয়েছে। এই উত্তরটি সবচেয়ে নিখুঁত, সবচেয়ে খারাপ সময়ে dangerous
স্প্রেগ

19

আপনি যা চান তা সম্পাদনের জন্য আমি আপনাকে 2 টি উপায় দেখাব:

প্রথম উপায়: যদি আপনার ক্ষেত্রটি শূন্য হয় তবে সেই ক্ষেত্রটির সিরিয়ালাইজেশন এড়াতে JsonProperty বৈশিষ্ট্যের সাথে আপনার ক্ষেত্রটি সাজান।

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 ব্যবহার করে এবং এটি সিরিয়ালাইজেশনের প্রতিবিম্ব ব্যবহার করে তাই যখন এটি সনাক্ত করা যায় (উদাহরণস্বরূপ) হোল্ডসরিয়ালাইজফিল্ডএক্স () পদ্ধতিটি ফিল্ডএক্সএক্স নামের ক্ষেত্রটি সিরিয়ালযুক্ত করা হবে না।


এটি ওয়েব এপিআই দ্বারা করা হয়নি, ওয়েব এপিআই সিরিয়ালাইজেশনের জন্য ডিফল্টরূপে Json.NET ব্যবহার করে। এই প্রক্রিয়াটি জসন.নাইট ওয়েব এপিআই নয়
হামিদ পৌরসাম

1
দ্বিতীয় সমাধানটি দুর্দান্ত কারণ এটি কিছু কিছু ক্ষেত্র আড়াল করার জন্য ডিটিওগুলির পুনর্লিখনের প্রয়োজন ছাড়াই ডোমেন অবজেক্ট প্রযুক্তি অজ্ঞেয়াদি রাখতে দেয়।
রাফায়েউ

17

আমি গেমটি করতে দেরি করেছি, তবে একটি বেনামে থাকা জিনিসটি কৌশলটি করতে পারে:

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

    var returnObjects = somethings.Select(x => new {
        Id = x.Id,
        OtherField = x.OtherField
    });

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

    return httpResponseMessage;
}

11

IgnoreDataMemberসম্পত্তি ব্যবহার করার চেষ্টা করুন

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

5

গ্রেটবিয়ার ৩০২ এর উত্তর হিসাবে প্রায় একই, তবে আমি অনুরোধ অনুযায়ী কন্ট্রাক্ট রিসলভার তৈরি করি।

1) একটি কাস্টম কন্ট্রাক্টরেসলভার তৈরি করুন

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

4

আপনি অটোম্যাপার এবং .Ignore()ম্যাপিং ব্যবহার করতে সক্ষম হবেন এবং তারপরে ম্যাপযুক্ত অবজেক্টটি প্রেরণ করতে পারবেন

CreateMap<Foo, Foo>().ForMember(x => x.Bar, opt => opt.Ignore());

3

স্রেফ এটিকে যুক্ত করে সূক্ষ্মভাবে কাজ করে: [ডেটা মেম্বার উপেক্ষা করুন]

সম্পত্তি হিসাবে শীর্ষে:

public class UserSettingsModel
{
    public string UserName { get; set; }
    [IgnoreDataMember]
    public DateTime Created { get; set; }
}

এটি অ্যাপিকন্ট্রোলারের সাথে কাজ করে। কোড:

[Route("api/Context/UserSettings")]
    [HttpGet, HttpPost]
    public UserSettingsModel UserSettings()
    {
        return _contextService.GetUserSettings();
    }

এছাড়াও সম্ভবত এর থেকে আরও ভাল সমাধান হ'ল "ব্যাক এন্ড" মডেলগুলি থেকে ভিউ-মডেলগুলি আলাদা করা, যাতে আপনি এই ঘোষণাটি এড়িয়ে যেতে পারেন। আমি নিজেকে প্রায়শই এই পরিস্থিতিতে উন্নত মনে করি।
দান্নেজাহ

0

কিছু কারণে [IgnoreDataMember]সর্বদা আমার পক্ষে কাজ করে না এবং আমি মাঝে মাঝে StackOverflowException(বা অনুরূপ) পাই । সুতরাং পরিবর্তে (বা অতিরিক্ত হিসাবে) আমি আমার POSTএপিআইতে সাইন ইন Objectsকরার সময় এই জাতীয় কিছু দেখার জন্য একটি প্যাটার্ন ব্যবহার শুরু করেছি :

[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একটিতে পাস করি এবং বিল্ট-ইন সিরিয়ালাইজারের কারণে সৃষ্ট অায়োড সমস্যাগুলি পুনরুদ্ধার হওয়ার পরে এটি রূপান্তর করে যা কখনও কখনও বস্তুগুলি বিশ্লেষণের সময় অসীম লুপের কারণ হয়ে থাকে।

যদি কারও কারও কারও পক্ষে জানা থাকে যে এটি কোনওভাবেই খারাপ ধারণা, তবে দয়া করে আমাকে জানান।

এটি লক্ষণীয় যে এইটিটিটি ফ্রেমওয়ার্ক শ্রেণি-সম্পত্তি যা সমস্যার কারণ হতে পারে তার জন্য নিম্নলিখিত কোড (যদি দুটি শ্রেণি একে অপরকে বোঝায়):

[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);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.