ASP.NET ওয়েব API তে পূর্ণসংখ্যার অ্যারে পাস করবেন?


427

আমার কাছে একটি এএসপি.নেট ওয়েব এপিআই (সংস্করণ 4) আরএসইটি পরিষেবা আছে যেখানে আমাকে পূর্ণসংখ্যার অ্যারে পাস করতে হবে।

আমার ক্রিয়া পদ্ধতিটি এখানে:

public IEnumerable<Category> GetCategories(int[] categoryIds){
// code to retrieve categories from database
}

এবং এটিই আমি চেষ্টা করেছি এমন ইউআরএল:

/Categories?categoryids=1,2,3,4

1
"/ বিভাগসমূহ? বিভাগগুলি = 1 এবং বিভাগীয় == এবং বিভাগগুলি = 3" এর মতো ক্যোরিস্ট্রিং ব্যবহার করার সময় আমি "অনুরোধের সামগ্রীতে একাধিক পরামিতি বাঁধতে পারি না" ত্রুটি পেয়ে যাচ্ছিলাম। আশা করি এটি এখানে এমন লোকদের নিয়ে আসে যারা এই একই ত্রুটি পেয়েছিল।
জোশ নোয়ে

1
@ জোশ আপনি কি [ফেরাউড়ি] ব্যবহার করেছেন? সর্বজনীন আইনিংরেবল <ক্যাটাগরি> গেটক্যাট্রিজ ([fromUri] int [] বিভাগসমূহ) {...}
অনুপ ক্যাটেল

2
@ ফ্র্যাঙ্কগোর্মন না, আমি ছিলাম না, যা আমার সমস্যা।
জোশ নোয়

উত্তর:


619

[FromUri]প্যারামিটারের আগে আপনাকে কেবল যুক্ত করা দরকার , দেখতে দেখতে:

GetCategories([FromUri] int[] categoryIds)

এবং অনুরোধ পাঠান:

/Categories?categoryids=1&categoryids=2&categoryids=3 

18
অ্যারেতে আমার কতগুলি ভেরিয়েবল আছে তা যদি আমি না জানি? এটা যদি 1000 এর মতো হয়? অনুরোধটি এমন হওয়া উচিত নয়।
সাহার চ।

7
এটি আমাকে একটি ত্রুটি দেয় "একই কী যুক্ত একটি আইটেম ইতিমধ্যে যুক্ত করা হয়েছে"। তবে এটি ক্যাটাগরিডগুলি [0] = 1 এবং বিভাগযুক্ত [1] = 2 এবং ইত্যাদি ... গ্রহণ করে না
ডাক্তার জোন্স

19
এটি গ্রহণযোগ্য উত্তর হওয়া উচিত - @ হেমংশু ভোজক: আপনার বাছাইয়ের সময় কি ঠিক নেই?
ডেভিড রেটেনব্যাকার

12
এর জন্য প্যারামিটার বাইন্ডিং সম্পর্কে কথা বলার জন্য এএসপি.নেট ওয়েব এপিআই ওয়েবসাইটের নিম্নলিখিত বিবৃতিটির কারণে এটির কারণটি রয়েছে : "প্যারামিটারটি যদি" ​​সরল "প্রকারের হয় তবে ওয়েব এপিআই ইউআরআই থেকে মান পেতে চেষ্টা করে Simple সাধারণ প্রকারের মধ্যে রয়েছে types নেট আদিম ধরণের (ইনট, বুল, ডাবল এবং আরও এগিয়ে), এবং টাইমস্প্যান, ডেটটাইম, গাইড, দশমিক এবং স্ট্রিং, এবং কোনও টাইপ রূপান্তরকারী স্ট্রিং থেকে রূপান্তর করতে পারে এমন কোনও প্রকার। " একটি int [] একটি সহজ ধরণের নয়।
Tr1stan

3
এটি আমার পক্ষে ভাল কাজ করে। একটি বিন্দু. সার্ভার কোডে অ্যারে প্যারামিটারটি কাজ করার জন্য প্রথমে আসতে হবে এবং অন্য কোনও প্যারামিটার পরে। অনুরোধে পরামিতিগুলিতে খাওয়ানোর সময়, আদেশটি গুরুত্বহীন।
সৃষ্টি

102

ফিলিপ ডাব্লু হিসাবে উল্লেখ করা হয়েছে, আপনাকে এ জাতীয় কাস্টম মডেল বাইন্ডার নিতে হবে (প্রকৃত ধরণের পরমের সাথে আবদ্ধ হতে সংশোধিত):

public IEnumerable<Category> GetCategories([ModelBinder(typeof(CommaDelimitedArrayModelBinder))]long[] categoryIds) 
{
    // do your thing
}

public class CommaDelimitedArrayModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        var key = bindingContext.ModelName;
        var val = bindingContext.ValueProvider.GetValue(key);
        if (val != null)
        {
            var s = val.AttemptedValue;
            if (s != null)
            {
                var elementType = bindingContext.ModelType.GetElementType();
                var converter = TypeDescriptor.GetConverter(elementType);
                var values = Array.ConvertAll(s.Split(new[] { ","},StringSplitOptions.RemoveEmptyEntries),
                    x => { return converter.ConvertFromString(x != null ? x.Trim() : x); });

                var typedValues = Array.CreateInstance(elementType, values.Length);

                values.CopyTo(typedValues, 0);

                bindingContext.Model = typedValues;
            }
            else
            {
                // change this line to null if you prefer nulls to empty arrays 
                bindingContext.Model = Array.CreateInstance(bindingContext.ModelType.GetElementType(), 0);
            }
            return true;
        }
        return false;
    }
}

এবং তারপরে আপনি বলতে পারেন:

/Categories?categoryids=1,2,3,4এবং এএসপি.নেট ওয়েব এপিআই সঠিকভাবে আপনার categoryIdsঅ্যারেকে আবদ্ধ করবে ।


10
এটি এসআরপি এবং / অথবা এসওসি লঙ্ঘন করতে পারে তবে আপনি সহজেই ModelBinderAttributeএটিকে উত্তরাধিকারীও করতে পারেন যাতে typeof()যুক্তি ব্যবহার করে শ্রমসাধ্য সিনট্যাক্সের পরিবর্তে এটি সরাসরি ব্যবহার করা যায় । আপনাকে যা করতে হবে তাই মত উত্তরাধিকারী হয়: CommaDelimitedArrayModelBinder : ModelBinderAttribute, IModelBinderএবং তারপর একটি ডিফল্ট কন্সট্রাকটর যে বেস বর্গ নিচে টাইপ সংজ্ঞা পাহাড় জমে প্রদান: public CommaDelimitedArrayModelBinder() : base(typeof(CommaDelimitedArrayModelBinder)) { }
স্লাইডারহাউরাসগুলি

অন্যথায়, আমি সত্যিই এই সমাধানটি পছন্দ করি এবং এটি আমার প্রকল্পে ব্যবহার করছি, তাই ... ধন্যবাদ। :)
স্লাইডার হাউসগুলি

আ একটি পার্শ্ব নোট, এই সমাধান জেনেরিক্স মতো কাজ করে না System.Collections.Generic.List<long>যেমন bindingContext.ModelType.GetElementType()শুধুমাত্র সমর্থন System.Arrayধরনের
ViRuSTriNiTy

@ ভাইরুস্ট্রিনিটি: এই প্রশ্ন এবং উত্তরটি অ্যারে সম্পর্কে বিশেষভাবে আলোচনা করে। আপনার যদি জেনেরিক তালিকা ভিত্তিক সমাধানের প্রয়োজন হয় তবে এটি বাস্তবায়নের পক্ষে মোটামুটি তুচ্ছ। আপনি কীভাবে এটি সম্পর্কে নিশ্চিত হন তা নিশ্চিত না হলে একটি আলাদা প্রশ্ন উত্সাহিত করতে নির্দ্বিধায়
মিঃচিফ

2
@ কোডমেঙ্কি: শরীরে অ্যারে দেওয়ানো একটি পোষ্ট অনুরোধের জন্য ভাল তা বোঝায়, তবে জিইটি অনুরোধগুলির কী হবে? এগুলির শরীরে সাধারণত কোনও সামগ্রী থাকে না।
স্টাকেক্স -

40

আমি সম্প্রতি এই প্রয়োজনীয়তাটি নিজেই পেরেছি এবং ActionFilterএটি হ্যান্ডেল করার জন্য আমি একটি বাস্তবায়ন করার সিদ্ধান্ত নিয়েছি ।

public class ArrayInputAttribute : ActionFilterAttribute
{
    private readonly string _parameterName;

    public ArrayInputAttribute(string parameterName)
    {
        _parameterName = parameterName;
        Separator = ',';
    }

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (actionContext.ActionArguments.ContainsKey(_parameterName))
        {
            string parameters = string.Empty;
            if (actionContext.ControllerContext.RouteData.Values.ContainsKey(_parameterName))
                parameters = (string) actionContext.ControllerContext.RouteData.Values[_parameterName];
            else if (actionContext.ControllerContext.Request.RequestUri.ParseQueryString()[_parameterName] != null)
                parameters = actionContext.ControllerContext.Request.RequestUri.ParseQueryString()[_parameterName];

            actionContext.ActionArguments[_parameterName] = parameters.Split(Separator).Select(int.Parse).ToArray();
        }
    }

    public char Separator { get; set; }
}

আমি এটি তেমনভাবে প্রয়োগ করছি (নোট করুন যে আমি 'আইডি' ব্যবহার করেছি, 'আইডস' নয়, যেমন এটি আমার রুটে নির্দিষ্ট করা আছে):

[ArrayInput("id", Separator = ';')]
public IEnumerable<Measure> Get(int[] id)
{
    return id.Select(i => GetData(i));
}

এবং সর্বজনীন ইউআরএল হ'ল:

/api/Data/1;2;3;4

আপনার নির্দিষ্ট চাহিদা মেটাতে আপনাকে এটিকে রিফ্যাক্টর করতে হতে পারে।


1
টাইপ ইন্ট হ'ল হার্ডকোডেড (ইন্ট। পার্স) আপনার সমাধানে। ইমো, @ মিস্টারফের সমাধান আরও ভাল
রেজন

27

যদি কারও প্রয়োজন হয় - এর POSTপরিবর্তে একই বা অনুরূপ জিনিস (মুছার মতো) অর্জনের জন্য FromUri, FromBodyক্লায়েন্টের পাশে (জেএস / জেকিউয়ারি) ফর্ম্যাট প্যারাম হিসাবে ব্যবহার করুন$.param({ '': categoryids }, true)

গ #:

public IHttpActionResult Remove([FromBody] int[] categoryIds)

JQuery:

$.ajax({
        type: 'POST',
        data: $.param({ '': categoryids }, true),
        url: url,
//...
});

জিনিসটি $.param({ '': categoryids }, true)হ'ল এটি। নেট পোস্ট =1&=2&=3প্যারামিটারের নাম এবং বন্ধনী ছাড়াই urlencoded মান ধারণ করবে will


2
কোনও পোস্টে অবলম্বন করার দরকার নেই। উত্তর @ লাভেল দেখুন।
আন্দ্রে ওয়ার্ল্যাং

3
আপনি কোনও ইউআরআইতে কতটা ডেটা প্রেরণ করতে পারেন তার সীমা রয়েছে। এবং মান অনুসারে, এটি কোনও জিইটি অনুরোধ হওয়া উচিত নয় যেহেতু এটি আসলে ডেটা সংশোধন করছে।
মূল্যবান 7

1
এবং আপনি এখানে ঠিক কোথায় পেয়েছেন? :)
মধ্যে Sofija

3
@ সোফিজা ওপি বলেছেন code to retrieve categories from database, এই পদ্ধতিটি জিইটি পদ্ধতি হওয়া উচিত, পোষ্ট নয়।
আজিমুথ

22

ওয়েব এপিআইতে অ্যারে প্যারামগুলি প্রেরণের সহজ উপায়

এপিআই

public IEnumerable<Category> GetCategories([FromUri]int[] categoryIds){
 // code to retrieve categories from database
}

জ্যাকোয়ারি: অনুরোধ প্যারাম হিসাবে JSON অবজেক্ট পাঠান

$.get('api/categories/GetCategories',{categoryIds:[1,2,3,4]}).done(function(response){
console.log(response);
//success response
});

এটি আপনার অনুরোধ URL টির মতো উত্পন্ন করবে ../api/categories/GetCategories?categoryIds=1&categoryIds=2&categoryIds=3&categoryIds=4


3
এটি কীভাবে গৃহীত উত্তরের চেয়ে আলাদা? jquery এর মাধ্যমে একটি এজাক্স অনুরোধ বাস্তবায়নের ব্যতিক্রম ছাড়া যার মূল পোস্টের সাথে কোনও সম্পর্ক ছিল না।
sksallaj

13

ওয়েবএপিআই থেকে কোনও জেএসওএন ফিরে পেতে আপনি কমা দ্বারা পৃথক হওয়া মানগুলি / মানগুলির একটি অ্যারে নেওয়ার জন্য আপনি এই কোডটি চেষ্টা করতে পারেন

 public class CategoryController : ApiController
 {
     public List<Category> Get(String categoryIDs)
     {
         List<Category> categoryRepo = new List<Category>();

         String[] idRepo = categoryIDs.Split(',');

         foreach (var id in idRepo)
         {
             categoryRepo.Add(new Category()
             {
                 CategoryID = id,
                 CategoryName = String.Format("Category_{0}", id)
             });
         }
         return categoryRepo;
     }
 }

 public class Category
 {
     public String CategoryID { get; set; }
     public String CategoryName { get; set; }
 } 

আউটপুট:

[
{"CategoryID":"4","CategoryName":"Category_4"}, 
{"CategoryID":"5","CategoryName":"Category_5"}, 
{"CategoryID":"3","CategoryName":"Category_3"} 
]

12

এএসপি.নেট কোর 2.0 সমাধান (সোয়াগার প্রস্তুত)

ইনপুট

DELETE /api/items/1,2
DELETE /api/items/1

কোড

সরবরাহকারী লিখুন (এমভিসি কীভাবে বাইন্ডার ব্যবহার করবে তা কীভাবে জানে)

public class CustomBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (context.Metadata.ModelType == typeof(int[]) || context.Metadata.ModelType == typeof(List<int>))
        {
            return new BinderTypeModelBinder(typeof(CommaDelimitedArrayParameterBinder));
        }

        return null;
    }
}

আসল দাতাগুলি লিখুন (অনুরোধ, ক্রিয়া, মডেল, প্রকার যা কিছু হোক না কেন সম্পর্কে সমস্ত ধরণের তথ্য অ্যাক্সেস করুন)

public class CommaDelimitedArrayParameterBinder : IModelBinder
{

    public Task BindModelAsync(ModelBindingContext bindingContext)
    {

        var value = bindingContext.ActionContext.RouteData.Values[bindingContext.FieldName] as string;

        // Check if the argument value is null or empty
        if (string.IsNullOrEmpty(value))
        {
            return Task.CompletedTask;
        }

        var ints = value?.Split(',').Select(int.Parse).ToArray();

        bindingContext.Result = ModelBindingResult.Success(ints);

        if(bindingContext.ModelType == typeof(List<int>))
        {
            bindingContext.Result = ModelBindingResult.Success(ints.ToList());
        }

        return Task.CompletedTask;
    }
}

এটি এমভিসির সাথে নিবন্ধন করুন

services.AddMvc(options =>
{
    // add custom binder to beginning of collection
    options.ModelBinderProviders.Insert(0, new CustomBinderProvider());
});

সোয়াগারের জন্য ভাল ডকুমেন্টেড কন্ট্রোলারের সাথে নমুনা ব্যবহার

/// <summary>
/// Deletes a list of items.
/// </summary>
/// <param name="itemIds">The list of unique identifiers for the  items.</param>
/// <returns>The deleted item.</returns>
/// <response code="201">The item was successfully deleted.</response>
/// <response code="400">The item is invalid.</response>
[HttpDelete("{itemIds}", Name = ItemControllerRoute.DeleteItems)]
[ProducesResponseType(typeof(void), StatusCodes.Status204NoContent)]
[ProducesResponseType(typeof(void), StatusCodes.Status404NotFound)]
public async Task Delete(List<int> itemIds)
=> await _itemAppService.RemoveRangeAsync(itemIds);

সম্পাদনা: মাইক্রোসফ্ট এই পদ্ধতির মাধ্যমে এই বাচ্চাদের ক্রিয়াকলাপের জন্য টাইপকনভার্টার ব্যবহার করার পরামর্শ দেয়। সুতরাং নীচের পোস্টারগুলির পরামর্শ অনুসরণ করুন এবং আপনার কাস্টম প্রকারটি স্কিমা ফিল্টার দিয়ে নথি করুন।


আমার মনে হয় আপনি যে এমএস রিকেন্ডেন্ডেশনটির কথা বলছেন তা এই উত্তর দ্বারা সন্তুষ্ট: স্ট্যাকওভারফ্লো.com
মাচাডো

তুমি কি এটা দেখেছিলে? github.com/aspnet/Mvc/pull/7967 দেখে মনে হচ্ছে যেন তারা কোনও বিশেষ বাইন্ডারের প্রয়োজন ছাড়াই ক্যোয়ারী স্ট্রিংয়ে তালিকা << যাকে> পার্সিং শুরু করার জন্য একটি সংযোজন করেছে। এছাড়াও আপনার লিঙ্ক করা পোস্টটি এসপনেট কোর নয় এবং আমি মনে করি না যে আমার পরিস্থিতির সাথে সহায়তা করে।
ভিক্টোরিও বেরেরা

সেরা, নন-হ্যাকি উত্তর।
এরিক ফিলিপস

7

আমি মূলত সমাধানটি ব্যবহার করেছি যা কয়েক বছর ধরে @ মিছিফ (এটি দুর্দান্ত কাজ করে)। কিন্তু যখন আমি এপিআই ডকুমেন্টেশনের জন্য আমার প্রকল্পে সোয়াগার যুক্ত করেছি তখন আমার শেষ পয়েন্টটি প্রদর্শিত হচ্ছে না

এটি আমার কিছুটা সময় নিয়েছিল, তবে আমি এটাই নিয়ে এসেছি। এটি সোয়াগার সহ কাজ করে এবং আপনার এপিআই পদ্ধতির স্বাক্ষরগুলি আরও পরিষ্কার দেখাচ্ছে:

শেষ পর্যন্ত আপনি করতে পারেন:

    // GET: /api/values/1,2,3,4 

    [Route("api/values/{ids}")]
    public IHttpActionResult GetIds(int[] ids)
    {
        return Ok(ids);
    }

WebApiConfig.cs

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Allow WebApi to Use a Custom Parameter Binding
        config.ParameterBindingRules.Add(descriptor => descriptor.ParameterType == typeof(int[]) && descriptor.ActionDescriptor.SupportedHttpMethods.Contains(HttpMethod.Get)
                                                           ? new CommaDelimitedArrayParameterBinder(descriptor)
                                                           : null);

        // Allow ApiExplorer to understand this type (Swagger uses ApiExplorer under the hood)
        TypeDescriptor.AddAttributes(typeof(int[]), new TypeConverterAttribute(typeof(StringToIntArrayConverter)));

        // Any existing Code ..

    }
}

একটি নতুন শ্রেণি তৈরি করুন: কমাডিলিমিটেডআরাইপ্যারামিটারবাইন্ডার সি

public class CommaDelimitedArrayParameterBinder : HttpParameterBinding, IValueProviderParameterBinding
{
    public CommaDelimitedArrayParameterBinder(HttpParameterDescriptor desc)
        : base(desc)
    {
    }

    /// <summary>
    /// Handles Binding (Converts a comma delimited string into an array of integers)
    /// </summary>
    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider,
                                             HttpActionContext actionContext,
                                             CancellationToken cancellationToken)
    {
        var queryString = actionContext.ControllerContext.RouteData.Values[Descriptor.ParameterName] as string;

        var ints = queryString?.Split(',').Select(int.Parse).ToArray();

        SetValue(actionContext, ints);

        return Task.CompletedTask;
    }

    public IEnumerable<ValueProviderFactory> ValueProviderFactories { get; } = new[] { new QueryStringValueProviderFactory() };
}

একটি নতুন শ্রেণি তৈরি করুন: স্ট্রিংটোইন্টআরাই কনভার্টার সি

public class StringToIntArrayConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }
}

মন্তব্য:

  • https://stackoverflow.com/a/47123965/862011 আমাকে সঠিক দিক নির্দেশ করেছে
  • [রুট] অ্যাট্রিবিউটটি ব্যবহার করার সময় সোয়াগার কেবলমাত্র আমার কমা বিস্মৃত শেষ পয়েন্টগুলি বেছে নিতে ব্যর্থ হয়েছিল

1
ক্ষেত্রে অন্য কারও কাছে এটি ব্যবহার করে গ্রন্থাগারগুলিতে তথ্য প্রয়োজন needs এখানে "কমাডেলিমেটেডআরাইপ্যারামিটারবাইন্ডার" ব্যবহার করা হচ্ছে। সিস্টেম.কলেশন.জেনারিক ব্যবহার করে; System.Linq ব্যবহার করে; System.Threading ব্যবহার করে; System.Threading.Tasks ব্যবহার করে; System.Web.Http.Controllers ব্যবহার করে; System.Web.Http.Metadata ব্যবহার করে; System.Web.Http. মডেলবাইন্ডিং ব্যবহার করে; System.Web.Http.ValueProvider ব্যবহার করে; সিস্টেম.ওয়েব.এইচটিপি.ভ্যালুপ্রোভিডার্স.প্রভাইডার ব্যবহার করে;
স্টেকডিএভি

6
public class ArrayInputAttribute : ActionFilterAttribute
{
    private readonly string[] _ParameterNames;
    /// <summary>
    /// 
    /// </summary>
    public string Separator { get; set; }
    /// <summary>
    /// cons
    /// </summary>
    /// <param name="parameterName"></param>
    public ArrayInputAttribute(params string[] parameterName)
    {
        _ParameterNames = parameterName;
        Separator = ",";
    }

    /// <summary>
    /// 
    /// </summary>
    public void ProcessArrayInput(HttpActionContext actionContext, string parameterName)
    {
        if (actionContext.ActionArguments.ContainsKey(parameterName))
        {
            var parameterDescriptor = actionContext.ActionDescriptor.GetParameters().FirstOrDefault(p => p.ParameterName == parameterName);
            if (parameterDescriptor != null && parameterDescriptor.ParameterType.IsArray)
            {
                var type = parameterDescriptor.ParameterType.GetElementType();
                var parameters = String.Empty;
                if (actionContext.ControllerContext.RouteData.Values.ContainsKey(parameterName))
                {
                    parameters = (string)actionContext.ControllerContext.RouteData.Values[parameterName];
                }
                else
                {
                    var queryString = actionContext.ControllerContext.Request.RequestUri.ParseQueryString();
                    if (queryString[parameterName] != null)
                    {
                        parameters = queryString[parameterName];
                    }
                }

                var values = parameters.Split(new[] { Separator }, StringSplitOptions.RemoveEmptyEntries)
                    .Select(TypeDescriptor.GetConverter(type).ConvertFromString).ToArray();
                var typedValues = Array.CreateInstance(type, values.Length);
                values.CopyTo(typedValues, 0);
                actionContext.ActionArguments[parameterName] = typedValues;
            }
        }
    }

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        _ParameterNames.ForEach(parameterName => ProcessArrayInput(actionContext, parameterName));
    }
}

ব্যবহার:

    [HttpDelete]
    [ArrayInput("tagIDs")]
    [Route("api/v1/files/{fileID}/tags/{tagIDs}")]
    public HttpResponseMessage RemoveFileTags(Guid fileID, Guid[] tagIDs)
    {
        _FileRepository.RemoveFileTags(fileID, tagIDs);
        return Request.CreateResponse(HttpStatusCode.OK);
    }

ইউরি অনুরোধ

http://localhost/api/v1/files/2a9937c7-8201-59b7-bc8d-11a9178895d0/tags/BBA5CD5D-F07D-47A9-8DEE-D19F5FA65F63,BBA5CD5D-F07D-47A9-8DEE-D19F5FA65F63

@ এলসা আপনি দয়া করে কোন টুকরোটি বুঝতে পারবেন না দয়া করে? আমি মনে করি কোডটি এটি নিজে ব্যাখ্যা করার জন্য যথেষ্ট স্পষ্ট। দুঃখিত, দুঃখিত, আমার এই সমস্ত কথা ইংরাজীতে ব্যাখ্যা করা মুশকিল।
Waninlezu

@ স্টিভ সিজেটি এখানে আমার পুনর্গঠিত সংস্করণ, আপনার ধারণার জন্য ধন্যবাদ
ওয়ানিনলেজু

এটি কি পৃথক /হিসাবে কাজ করবে ? তারপরে আপনি পেতে পারেন: ডিএনএস / রুট / মাইস্টফ / পাথ / টু / কিছু / রিসোর্সে ম্যাপ করা হয়েছেpublic string GetMyStuff(params string[] pathBits)
RoboJ1M

6

একটি কাস্টম মডেলবাইন্ডার ব্যবহার না করে, আপনি টাইপকনভার্টারের সাথে একটি কাস্টম প্রকারও ব্যবহার করতে পারেন।

[TypeConverter(typeof(StrListConverter))]
public class StrList : List<string>
{
    public StrList(IEnumerable<string> collection) : base(collection) {}
}

public class StrListConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        if (value == null)
            return null;

        if (value is string s)
        {
            if (string.IsNullOrEmpty(s))
                return null;
            return new StrList(s.Split(','));
        }
        return base.ConvertFrom(context, culture, value);
    }
}

সুবিধাটি হ'ল এটি ওয়েব এপিআই পদ্ধতির পরামিতিগুলিকে খুব সহজ করে তোলে। এমনকি আপনার [[থেকে ইউরি]] নির্দিষ্ট করার দরকার নেই।

public IEnumerable<Category> GetCategories(StrList categoryIds) {
  // code to retrieve categories from database
}

এই উদাহরণটি স্ট্রিংগুলির তালিকার জন্য, তবে আপনি categoryIds.Select(int.Parse)কেবল এর পরিবর্তে কোনও ইন্টারলিস্ট লিখতে বা লিখতে পারেন।


বুঝতে পারেন না কেন এই সমাধানটি বেশি ভোট পেল না। এটি দুর্দান্ত এবং পরিষ্কার এবং কাস্টম বাইন্ডার এবং স্টাফ যোগ না করে swagger এর সাথে কাজ করে।
থাইমে

আমার মতে সেরা / পরিষ্কার উত্তর। ধন্যবাদ ফিলিপএম!
লে বাউয়ার্স

5

আপনি যদি পূর্ণসংখ্যার সহজ / সহজ তালিকা তৈরি করতে চান তবে এটি হ'ল কমা (,) পৃথক স্ট্রিংয়ের তালিকাটি গ্রহণ করুন এবং এটি পূর্ণসংখ্যার তালিকায় রূপান্তর করুন [[fromUri] attriubte.yur url বর্ণনাকে ভুলে যাবেন না:

...? আইডি = 71 & accountID = 1,2,3,289,56

public HttpResponseMessage test([FromUri]int ID, [FromUri]string accountID)
{
    List<int> accountIdList = new List<int>();
    string[] arrAccountId = accountId.Split(new char[] { ',' });
    for (var i = 0; i < arrAccountId.Length; i++)
    {
        try
        {
           accountIdList.Add(Int32.Parse(arrAccountId[i]));
        }
        catch (Exception)
        {
        }
    }
}

কেন আপনি ন্যায়বিচারের List<string>পরিবর্তে ব্যবহার করবেন string? এটিতে কেবল একটি স্ট্রিং থাকবে যা 1,2,3,289,56আপনার উদাহরণে রয়েছে। আমি একটি সম্পাদনা পরামর্শ দেব।
ড্যানিয়েল তুল্প

আমার জন্য কাজ করেছেন। আমি অবাক হয়েছি যে আমার নিয়ামক List<Guid>যদিও একটি স্বয়ংক্রিয়ভাবে আবদ্ধ হবে না । Asp.net মূল নোটটি টীকাটি রয়েছে [FromQuery]এবং এটির প্রয়োজন নেই।
kitsu.eb

2
এক-লাইন লিনক সংস্করণের জন্য: int [] অ্যাকাউন্টআইডিআরাই = অ্যাকাউন্টআইডি.স্প্লিট (',')। আমি ধরা এড়াতে চাই যেহেতু এটি খারাপ ডেটাতে পাস করা কাউকে মাস্ক করবে।
স্টিভ সিও ইন

3

[টাইপ] পদ্ধতিটি [HttpPost] করুন, একটি মডেল তৈরি করুন যার একটি int [] প্যারামিটার রয়েছে এবং জেসন সহ পোস্ট করুন:

/* Model */
public class CategoryRequestModel 
{
    public int[] Categories { get; set; }
}

/* WebApi */
[HttpPost]
public HttpResponseMessage GetCategories(CategoryRequestModel model)
{
    HttpResponseMessage resp = null;

    try
    {
        var categories = //your code to get categories

        resp = Request.CreateResponse(HttpStatusCode.OK, categories);

    }
    catch(Exception ex)
    {
        resp = Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
    }

    return resp;
}

/* jQuery */
var ajaxSettings = {
    type: 'POST',
    url: '/Categories',
    data: JSON.serialize({Categories: [1,2,3,4]}),
    contentType: 'application/json',
    success: function(data, textStatus, jqXHR)
    {
        //get categories from data
    }
};

$.ajax(ajaxSettings);

আপনি আপনার অ্যারেটিকে একটি ক্লাসে আবৃত করছেন - এটি দুর্দান্ত কাজ করবে (এমভিসি / ওয়েবএপিআই সত্ত্বেও)। ওপিতে একটি মোড়কের ক্লাস ছাড়াই বিন্যাস সম্পর্কে আবদ্ধ ছিল।
মিচিফ

1
আসল সমস্যাটি মোড়কের ক্লাস ছাড়াই এটি করার বিষয়ে কিছুই বলে না, কেবল তারা জটিল বস্তুর জন্য ক্যোয়ারী প্যারাম ব্যবহার করতে চেয়েছিল। আপনি যদি সেই পথ থেকে খুব দূরে যান তবে আপনি এমন একটি পয়েন্টে পৌঁছে যাবেন যেখানে সত্যিকারের জটিল জেএস বস্তুটি তুলতে আপনার এপিআই দরকার, এবং ক্যোয়ারী পারম আপনাকে ব্যর্থ করবে। পাশাপাশি এটি এটি করতে শিখতে পারে যা প্রতিবারের মতো কার্যকর হবে।
কোডমনকি

public IEnumerable<Category> GetCategories(int[] categoryIds){- হ্যাঁ আপনি ধারণা করতে পারেন বিভিন্ন উপায়ে। তবে অনেক সময়, আমি মোড়ক তৈরির প্রয়োজনে মোড়ক ক্লাস তৈরি করতে চাই না। আপনার যদি জটিল অবজেক্ট থাকে তবে তা কেবল কাজ করবে। এই সহজ ক্ষেত্রে সমর্থন করা বাক্সের বাইরে কাজ করে না, তাই ওপি।
মিঃচিফ

3
এর মাধ্যমে POSTএটি করা আসলে বিশ্রামদৃষ্টির বিরুদ্ধ against সুতরাং এই জাতীয় এপিআই একটি বিশ্রামের এপিআই হবে না।
আজিমুথ

1
@ আজিমুথ আমাকে এক হাতে একটি দৃষ্টান্ত দেন, অন্য হাতে নেট নেট নিয়ে কী কাজ করে
কোডমনেকি

3

অথবা আপনি সীমাবদ্ধ আইটেমগুলির একটি স্ট্রিং পাস করতে এবং এটিকে একটি অ্যারে বা প্রাপ্তির শেষে তালিকায় রাখতে পারেন।


2

আমি এই বিষয়টিকে এইভাবে সম্বোধন করেছি।

আমি এপিআই-তে একটি পোস্ট বার্তা ব্যবহার করে ডেটা হিসাবে পূর্ণসংখ্যার তালিকা প্রেরণ করি।

তারপরে আমি ডেটাটি একটি অযৌক্তিক হিসাবে ফিরিয়ে দিয়েছি।

প্রেরণ কোডটি নিম্নরূপ:

public override IEnumerable<Contact> Fill(IEnumerable<int> ids)
{
    IEnumerable<Contact> result = null;
    if (ids!=null&&ids.Count()>0)
    {
        try
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("http://localhost:49520/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                String _endPoint = "api/" + typeof(Contact).Name + "/ListArray";

                HttpResponseMessage response = client.PostAsJsonAsync<IEnumerable<int>>(_endPoint, ids).Result;
                response.EnsureSuccessStatusCode();
                if (response.IsSuccessStatusCode)
                {
                    result = JsonConvert.DeserializeObject<IEnumerable<Contact>>(response.Content.ReadAsStringAsync().Result);
                }

            }

        }
        catch (Exception)
        {

        }
    }
    return result;
}

প্রাপ্তি কোডটি নিম্নরূপ:

// POST api/<controller>
[HttpPost]
[ActionName("ListArray")]
public IEnumerable<Contact> Post([FromBody]IEnumerable<int> ids)
{
    IEnumerable<Contact> result = null;
    if (ids != null && ids.Count() > 0)
    {
        return contactRepository.Fill(ids);
    }
    return result;
}

এটি একটি রেকর্ড বা অনেক রেকর্ডের জন্য ঠিক কাজ করে। ফিলটি ড্যাপার এক্সটেনশনগুলি ব্যবহার করে একটি ওভারলোডেড পদ্ধতি:

public override IEnumerable<Contact> Fill(IEnumerable<int> ids)
{
    IEnumerable<Contact> result = null;
    if (ids != null && ids.Count() > 0)
    {
        using (IDbConnection dbConnection = ConnectionProvider.OpenConnection())
        {
            dbConnection.Open();
            var predicate = Predicates.Field<Contact>(f => f.id, Operator.Eq, ids);
            result = dbConnection.GetList<Contact>(predicate);
            dbConnection.Close();
        }
    }
    return result;
}

এটি আপনাকে একটি যৌগিক টেবিল (আইডি তালিকা) থেকে ডেটা আনতে এবং তারপরে লক্ষ্য সারণী থেকে আপনার আগ্রহী রেকর্ডগুলি ফিরিয়ে আনতে সহায়তা করে।

আপনি একটি দর্শন দিয়ে একই করতে পারেন, তবে এটি আপনাকে আরও কিছুটা নিয়ন্ত্রণ এবং নমনীয়তা দেয়।

এছাড়াও, আপনি ডাটাবেস থেকে কী চাইছেন তার বিশদ কোয়েরি স্ট্রিংয়ে দেখানো হয়নি। আপনার কোনও সিএসভি ফাইল থেকে রূপান্তর করতে হবে না।

ওয়েব এপিআই ২.০ ইন্টারফেসের মতো কোনও সরঞ্জাম ব্যবহার করার সময় আপনাকে মনে রাখতে হবে যে গেট, পুট, পোস্ট, ডিলিট, হেড ইত্যাদি ফাংশনগুলির একটি সাধারণ ব্যবহার রয়েছে তবে এটি ব্যবহারের মধ্যে সীমাবদ্ধ নয়।

সুতরাং, পোস্টটি সাধারণত ওয়েব এপিআই ইন্টারফেসে তৈরি প্রসঙ্গে ব্যবহৃত হয়, তবে এটি সেই ব্যবহারের মধ্যেই সীমাবদ্ধ নয়। এটি একটি নিয়মিত এইচটিএমএল কল যা এইচটিএমএল অনুশীলনের দ্বারা অনুমোদিত যে কোনও উদ্দেশ্যে ব্যবহার করা যেতে পারে।

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

ওয়েব এপিআই ২.x ইন্টারফেসে নামকরণের কনফারেন্স এবং নিয়মিত ওয়েব কলিংয়ের ব্যবহারের অর্থ হল আপনি ওয়েব এপিটিতে একটি কল পাঠিয়েছেন যা স্নোপারদের ভেবে ভ্রান্ত করে যে আপনি সত্যিই অন্য কিছু করছেন। উদাহরণস্বরূপ, ডেটা সত্যিই উদ্ধার করতে আপনি "পোস্ট" ব্যবহার করতে পারেন।


2

আমি একটি কাস্টম মডেল বাইন্ডার তৈরি করেছি যা কোনও কমা দ্বারা পৃথক করা মানগুলিকে (কেবলমাত্র আদিম, দশমিক, ভাসমান, স্ট্রিং) তাদের সংশ্লিষ্ট অ্যারেতে রূপান্তর করে।

public class CommaSeparatedToArrayBinder<T> : IModelBinder
    {
        public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            Type type = typeof(T);
            if (type.IsPrimitive || type == typeof(Decimal) || type == typeof(String) || type == typeof(float))
            {
                ValueProviderResult val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
                if (val == null) return false;

                string key = val.RawValue as string;
                if (key == null) { bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Wrong value type"); return false; }

                string[] values = key.Split(',');
                IEnumerable<T> result = this.ConvertToDesiredList(values).ToArray();
                bindingContext.Model = result;
                return true;
            }

            bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Only primitive, decimal, string and float data types are allowed...");
            return false;
        }

        private IEnumerable<T> ConvertToDesiredArray(string[] values)
        {
            foreach (string value in values)
            {
                var val = (T)Convert.ChangeType(value, typeof(T));
                yield return val;
            }
        }
    }

এবং কিভাবে নিয়ামক ব্যবহার করবেন:

 public IHttpActionResult Get([ModelBinder(BinderType = typeof(CommaSeparatedToArrayBinder<int>))] int[] ids)
        {
            return Ok(ids);
        }

ধন্যবাদ, আমি এটিকে সামান্য পরিশ্রমে 3.1 নেটপোর্টে রেখেছি এবং এটি কার্যকর! গৃহীত উত্তরটি বহুবার বহুবার পরম নাম উল্লেখ করার প্রয়োজনে সমস্যাটি সমাধান করে না এবং নেটকোর ৩.১
বোগদান মার্ট

0

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

আপনি এইভাবে ব্যবহার করেন:

public class MustBeListAndContainAttribute : ValidationAttribute
{
    private Regex regex = null;
    public bool RemoveDuplicates { get; }
    public string Separator { get; }
    public int MinimumItems { get; }
    public int MaximumItems { get; }

    public MustBeListAndContainAttribute(string regexEachItem,
        int minimumItems = 1,
        int maximumItems = 0,
        string separator = ",",
        bool removeDuplicates = false) : base()
    {
        this.MinimumItems = minimumItems;
        this.MaximumItems = maximumItems;
        this.Separator = separator;
        this.RemoveDuplicates = removeDuplicates;

        if (!string.IsNullOrEmpty(regexEachItem))
            regex = new Regex(regexEachItem, RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase);
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var listOfdValues = (value as List<string>)?[0];

        if (string.IsNullOrWhiteSpace(listOfdValues))
        {
            if (MinimumItems > 0)
                return new ValidationResult(this.ErrorMessage);
            else
                return null;
        };

        var list = new List<string>();

        list.AddRange(listOfdValues.Split(new[] { Separator }, System.StringSplitOptions.RemoveEmptyEntries));

        if (RemoveDuplicates) list = list.Distinct().ToList();

        var prop = validationContext.ObjectType.GetProperty(validationContext.MemberName);
        prop.SetValue(validationContext.ObjectInstance, list);
        value = list;

        if (regex != null)
            if (list.Any(c => string.IsNullOrWhiteSpace(c) || !regex.IsMatch(c)))
                return new ValidationResult(this.ErrorMessage);

        return null;
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.