এএসপি.নেট এমভিসি অস্পষ্ট কর্মের পদ্ধতিগুলি


135

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

উদাহরণ স্বরূপ...

Items/{action}/ParentName/ItemName
Items/{action}/1234-4321-1234-4321

এখানে আমার ক্রিয়া পদ্ধতিগুলি রয়েছে ( Removeক্রিয়া পদ্ধতিও রয়েছে) ...

// Method #1
public ActionResult Assign(string parentName, string itemName) { 
    // Logic to retrieve item's ID here...
    string itemId = ...;
    return RedirectToAction("Assign", "Items", new { itemId });
}

// Method #2
public ActionResult Assign(string itemId, string searchTerm, int? page) { ... }

এবং এখানে রুটগুলি ...

routes.MapRoute("AssignRemove",
                "Items/{action}/{itemId}",
                new { controller = "Items" }
                );

routes.MapRoute("AssignRemovePretty",
                "Items/{action}/{parentName}/{itemName}",
                new { controller = "Items" }
                );

আমি বুঝতে পারি যে ত্রুটি কেন ঘটছে, যেহেতু pageপ্যারামিটারটি শূন্য হতে পারে তবে আমি এটি সমাধান করার সর্বোত্তম উপায়টি বের করতে পারি না। আমার ডিজাইনটি কি শুরু করা খারাপ? আমি Method #1অনুসন্ধানের পরামিতিগুলি অন্তর্ভুক্ত করার জন্য যুক্তিটির সই বাড়াতে এবং যুক্তিটি Method #2একটি ব্যক্তিগত পদ্ধতিতে সরিয়ে নিয়ে যাব যে তারা দুজনেই ডাকবে বলে আমি ভেবেছিলাম, তবে আমি বিশ্বাস করি না যে প্রকৃতপক্ষে অস্পষ্টতাটি সমাধান হবে।

কোন সাহায্যের ব্যাপকভাবে প্রশংসা হবে।


আসল সমাধান (লেবির উত্তরের ভিত্তিতে)

আমি নিম্নলিখিত ক্লাস যুক্ত করেছি ...

public class RequireRouteValuesAttribute : ActionMethodSelectorAttribute {
    public RequireRouteValuesAttribute(string[] valueNames) {
        ValueNames = valueNames;
    }

    public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
        bool contains = false;
        foreach (var value in ValueNames) {
            contains = controllerContext.RequestContext.RouteData.Values.ContainsKey(value);
            if (!contains) break;
        }
        return contains;
    }

    public string[] ValueNames { get; private set; }
}

এবং তারপরে অ্যাকশন পদ্ধতিগুলি সজ্জিত করুন ...

[RequireRouteValues(new[] { "parentName", "itemName" })]
public ActionResult Assign(string parentName, string itemName) { ... }

[RequireRouteValues(new[] { "itemId" })]
public ActionResult Assign(string itemId) { ... }

3
প্রকৃত বাস্তবায়ন পোস্ট করার জন্য ধন্যবাদ। এটি নিশ্চিতভাবে একই সমস্যাযুক্ত লোকদের সহায়তা করে। আমার আজ যেমন ছিল :
পাওলো সান্টোস

4
অ্যামেজিং! অপ্রাপ্তবয়স্ক পরিবর্তনের পরামর্শ: (ইমো সত্যই কার্যকর) 1) প্যারাম স্ট্রিং [] মানটির নামগুলি বিশিষ্ট ঘোষণাকে আরও সংক্ষিপ্ত করতে এবং (অগ্রাধিকার) 2) ইসভিডালফরেক্সট পদ্ধতি পদ্ধতির বডিটি প্রতিস্থাপন করুনreturn ValueNames.All(v => controllerContext.RequestContext.RouteData.Values.ContainsKey(v));
বেনজমিন পোডসজুন

2
আমার একই ক্যোরিস্ট্রিং প্যারামিটার সমস্যা ছিল। আপনার যদি প্রয়োজনীয়তার জন্য বিবেচনা করা সেই প্যারামিটারগুলির প্রয়োজন হয় তবে contains = ...এই জাতীয় contains = controllerContext.RequestContext.RouteData.Values.ContainsKey(value) || controllerContext.RequestContext.HttpContext.Request.Params.AllKeys.Contains(value);
কোনও কিছুর

3
এতে সতর্কতার নোট: প্রয়োজনীয় প্যারামিটারগুলি অবশ্যই নাম অনুসারে প্রেরণ করতে হবে। যদি আপনার অ্যাকশন পদ্ধতির প্যারামিটারটি একটি জটিল ধরণের নাম হিসাবে তার বৈশিষ্ট্যগুলিতে পাস করে (এবং এমভিসিগুলিকে জটিল ধরণেরে ম্যাসেজ করতে দেয়), এই সিস্টেমটি ব্যর্থ হয় কারণ নাম ক্যোরিস্ট্রিং কীগুলিতে নেই। উদাহরণস্বরূপ, এটি কাজ করবে না:, ActionResult DoSomething(Person p)যেখানে Personবিভিন্ন সরল বৈশিষ্ট্য রয়েছে যেমন Nameএবং এটিতে অনুরোধগুলি সরাসরি সম্পত্তি নামের সাথে করা হয় (যেমন, /dosomething/?name=joe+someone&other=properties)।
পৃষ্ঠপোষক

4
আপনি যদি এমভিসি 4 ব্যবহার করে থাকেন তবে আপনার controllerContext.HttpContext.Request[value] != nullপরিবর্তে ব্যবহার করা উচিত controllerContext.RequestContext.RouteData.Values.ContainsKey(value); তবে তবুও কাজের একটি সুন্দর অংশ।
কেভিন ফারুগিয়া

উত্তর:


180

এমভিসি সম্পূর্ণ স্বাক্ষরের ভিত্তিতে ওভারলোডিং পদ্ধতিটিকে সমর্থন করে না, সুতরাং এটি ব্যর্থ হবে:

public ActionResult MyMethod(int someInt) { /* ... */ }
public ActionResult MyMethod(string someString) { /* ... */ }

যাইহোক, এটি বৈশিষ্ট্যের উপর ভিত্তি করে সমর্থন পদ্ধতি ওভারলোডিং করে:

[RequireRequestValue("someInt")]
public ActionResult MyMethod(int someInt) { /* ... */ }

[RequireRequestValue("someString")]
public ActionResult MyMethod(string someString) { /* ... */ }

public class RequireRequestValueAttribute : ActionMethodSelectorAttribute {
    public RequireRequestValueAttribute(string valueName) {
        ValueName = valueName;
    }
    public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
        return (controllerContext.HttpContext.Request[ValueName] != null);
    }
    public string ValueName { get; private set; }
}

উপরের উদাহরণে, গুণাবলীটি সহজভাবে বলে "কী xxx অনুরোধে উপস্থিত থাকলে এই পদ্ধতিটি মেলে " " আপনি যদি রুটগুলির মধ্যে অন্তর্ভুক্ত থাকা তথ্য (কন্ট্রোলারকন্টেক্সট.রেকুয়েস্টকন্টেক্সট) এর মাধ্যমেও ফিল্টার করতে পারেন তবে যদি এটি আপনার উদ্দেশ্যগুলির পক্ষে আরও ভাল করে।


এটি আমার যা প্রয়োজন ঠিক তা শেষ হয়েছিল। আপনার প্রস্তাব অনুসারে, আমার নিয়ন্ত্রণকারী কনটেক্সট.রেকুয়েস্টকন্টেক্সট ব্যবহার করা দরকার।
জোনাথন ফ্রিল্যান্ড

4
নিস! আমি এখনও প্রয়োজনীয়তার প্রয়োজনীয়তা বৈশিষ্ট্যটি দেখিনি। এটি জানা ভাল।
কোডারডেনিস

1
আমরা বেশ কয়েকটি উত্সের মতো মূল্যগুলি পেতে ভ্যালুপ্রাইভাইডারটি ব্যবহার করতে পারি যেমন: কন্ট্রোলার কনটেক্সট ont কন্ট্রোলার.ভালিউপ্রভাইডার.গেটভ্যালু (মান);
Jone Polvora

...RouteData.Valuesপরিবর্তে আমি পরে গিয়েছিলাম , তবে এটি "কাজ করে"। এটি একটি ভাল প্যাটার্নটি বিতর্কের জন্য উন্মুক্ত কিনা। :)
bambams

1
আমি আমার পূর্ববর্তী সম্পাদনাটি প্রত্যাখ্যান করেছিলাম তাই আমি কেবল মন্তব্য করব: [অ্যাট্রিবিউট ইউজেজ (অ্যাট্রিবিউটট্রেজেটস অল, মল্টিপলিটল = সত্য))]
মেজান

7

আপনার রুটে পরামিতি {roleId}, {applicationName}এবং{roleName} আপনার কর্ম পদ্ধতিতে প্যারামিটার নাম মিলছে না। আমি জানি না যে এটি গুরুত্বপূর্ণ কিনা তবে এটি আপনার উদ্দেশ্য কী তা নির্ধারণ করা আরও কঠিন করে তোলে।

আপনার আইটেমআইডি কি এমন একটি প্যাটার্নের সাথে মিলে যায় যা রেজেক্সের মাধ্যমে মিলে যায়? যদি তা হয় তবে আপনি নিজের রুটে একটি সংযোজন যুক্ত করতে পারেন যাতে প্যাটার্নের সাথে মেলে এমন ইউআরএল কেবল আইটেম আইড যুক্ত হিসাবে চিহ্নিত করা যায়।

যদি আপনার আইটেমআইডিতে কেবল অঙ্ক থাকে তবে এটি কাজ করবে:

routes.MapRoute("AssignRemove",
                "Items/{action}/{itemId}",
                new { controller = "Items" },
                new { itemId = "\d+" }
                );

সম্পাদনা করুন: আপনি AssignRemovePrettyরুটে একটি সীমাবদ্ধতাও যুক্ত করতে পারেন যাতে {parentName}এবং উভয়ই{itemName} প্রয়োজন হয়।

সম্পাদনা 2: এছাড়াও, যেহেতু আপনার প্রথম ক্রিয়াটি আপনার দ্বিতীয় ক্রিয়ায় কেবল পুনঃনির্দেশ করছে তাই আপনি প্রথমটির নাম পরিবর্তন করে কিছুটা অস্পষ্টতা দূর করতে পারেন।

// Method #1
public ActionResult AssignRemovePretty(string parentName, string itemName) { 
    // Logic to retrieve item's ID here...
    string itemId = ...;
    return RedirectToAction("Assign", itemId);
}

// Method #2
public ActionResult Assign(string itemId, string searchTerm, int? page) { ... }

তারপরে যথাযথ পদ্ধতিটি ডাকতে বাধ্য করার জন্য আপনার রুটে অ্যাকশন নামগুলি উল্লেখ করুন:

routes.MapRoute("AssignRemove",
                "Items/Assign/{itemId}",
                new { controller = "Items", action = "Assign" },
                new { itemId = "\d+" }
                );

routes.MapRoute("AssignRemovePretty",
                "Items/Assign/{parentName}/{itemName}",
                new { controller = "Items", action = "AssignRemovePretty" },
                new { parentName = "\w+", itemName = "\w+" }
                );

1
দুঃখিত ডেনিস, প্যারামিটারগুলি আসলে মিলছে। আমি প্রশ্ন স্থির করেছি। আমি পুনরায় সংযমের চেষ্টা করব এবং আপনার কাছে ফিরে আসব। ধন্যবাদ!
জোনাথন ফ্রিল্যান্ড

আপনার দ্বিতীয় সম্পাদনাটি আমাকে সাহায্য করেছিল, তবে শেষ পর্যন্ত লেবির পরামর্শই এই চুক্তিটি সিল করে দেয়। আবার ধন্যবাদ!
জোনাথন ফ্রিল্যান্ড

7

আর একটি পদ্ধতির মধ্যে কোনও পদ্ধতির নাম পরিবর্তন করা যাতে কোনও বিরোধ না হয়। উদাহরণ স্বরূপ

// GET: /Movies/Delete/5
public ActionResult Delete(int id = 0)

// POST: /Movies/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id = 0)

Http://www.asp.net/mvc/tutorials/getting-started-with-mvc3-part9-cs দেখুন


3

সম্প্রতি আমি মোকাবিলা করতে হয়েছে এমন বিস্তৃত পরিস্থিতিগুলির সমর্থন করার জন্য @ লেবির উত্তরটির উন্নতি করার সুযোগ নিয়েছি, যেমন: একাধিক প্যারামিটার সমর্থন, তাদের কোনওটির সাথে (তাদের পরিবর্তে) মেলে এমনকি তাদের কোনওটির সাথেও মেলে না।

আমি এখন যে বৈশিষ্ট্যটি ব্যবহার করছি তা এখানে:

/// <summary>
/// Flags an Action Method valid for any incoming request only if all, any or none of the given HTTP parameter(s) are set,
/// enabling the use of multiple Action Methods with the same name (and different signatures) within the same MVC Controller.
/// </summary>
public class RequireParameterAttribute : ActionMethodSelectorAttribute
{
    public RequireParameterAttribute(string parameterName) : this(new[] { parameterName })
    {
    }

    public RequireParameterAttribute(params string[] parameterNames)
    {
        IncludeGET = true;
        IncludePOST = true;
        IncludeCookies = false;
        Mode = MatchMode.All;
    }

    public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
    {
        switch (Mode)
        {
            case MatchMode.All:
            default:
                return (
                    (IncludeGET && ParameterNames.All(p => controllerContext.HttpContext.Request.QueryString.AllKeys.Contains(p)))
                    || (IncludePOST && ParameterNames.All(p => controllerContext.HttpContext.Request.Form.AllKeys.Contains(p)))
                    || (IncludeCookies && ParameterNames.All(p => controllerContext.HttpContext.Request.Cookies.AllKeys.Contains(p)))
                    );
            case MatchMode.Any:
                return (
                    (IncludeGET && ParameterNames.Any(p => controllerContext.HttpContext.Request.QueryString.AllKeys.Contains(p)))
                    || (IncludePOST && ParameterNames.Any(p => controllerContext.HttpContext.Request.Form.AllKeys.Contains(p)))
                    || (IncludeCookies && ParameterNames.Any(p => controllerContext.HttpContext.Request.Cookies.AllKeys.Contains(p)))
                    );
            case MatchMode.None:
                return (
                    (!IncludeGET || !ParameterNames.Any(p => controllerContext.HttpContext.Request.QueryString.AllKeys.Contains(p)))
                    && (!IncludePOST || !ParameterNames.Any(p => controllerContext.HttpContext.Request.Form.AllKeys.Contains(p)))
                    && (!IncludeCookies || !ParameterNames.Any(p => controllerContext.HttpContext.Request.Cookies.AllKeys.Contains(p)))
                    );
        }
    }

    public string[] ParameterNames { get; private set; }

    /// <summary>
    /// Set it to TRUE to include GET (QueryStirng) parameters, FALSE to exclude them:
    /// default is TRUE.
    /// </summary>
    public bool IncludeGET { get; set; }

    /// <summary>
    /// Set it to TRUE to include POST (Form) parameters, FALSE to exclude them:
    /// default is TRUE.
    /// </summary>
    public bool IncludePOST { get; set; }

    /// <summary>
    /// Set it to TRUE to include parameters from Cookies, FALSE to exclude them:
    /// default is FALSE.
    /// </summary>
    public bool IncludeCookies { get; set; }

    /// <summary>
    /// Use MatchMode.All to invalidate the method unless all the given parameters are set (default).
    /// Use MatchMode.Any to invalidate the method unless any of the given parameters is set.
    /// Use MatchMode.None to invalidate the method unless none of the given parameters is set.
    /// </summary>
    public MatchMode Mode { get; set; }

    public enum MatchMode : int
    {
        All,
        Any,
        None
    }
}

আরও তথ্য এবং কীভাবে প্রয়োগের নমুনাগুলির জন্য এই ব্লগ পোস্টটি আমি এই বিষয়ে লিখেছি তা পরীক্ষা করে দেখুন ।


ধন্যবাদ, দুর্দান্ত উন্নতি! তবে প্যারামিটারনামস কর্টে সেট করা নেই
nvirth

0
routes.MapRoute("AssignRemove",
                "Items/{parentName}/{itemName}",
                new { controller = "Items", action = "Assign" }
                );

আপনার রুটগুলি পরীক্ষা করতে MVC কে পরীক্ষার রুটগুলির লাইব্রেরি ব্যবহারের বিষয়টি বিবেচনা করুন

"Items/parentName/itemName".Route().ShouldMapTo<Items>(x => x.Assign("parentName", itemName));
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.