Programing

ASP.NET MVC Framework에서 여러 제출 단추를 어떻게 처리합니까?

lottogame 2020. 9. 30. 08:40
반응형

ASP.NET MVC Framework에서 여러 제출 단추를 어떻게 처리합니까?


동일한 양식에서 여러 제출 단추를 쉽게 처리 할 수있는 방법이 있습니까? 예:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" value="Send" />
<input type="submit" value="Cancel" />
<% Html.EndForm(); %>

ASP.NET Framework Beta에서이 작업을 수행하는 방법을 알고 계십니까? 내가 검색 한 모든 예제에는 단일 버튼이 있습니다.


다음은 Maartin Balliauw 의 게시물과 댓글을 기반으로 여러 제출 버튼 문제에 대한 대부분의 깨끗한 속성 기반 솔루션 입니다.

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MultipleButtonAttribute : ActionNameSelectorAttribute
{
    public string Name { get; set; }
    public string Argument { get; set; }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        var isValidName = false;
        var keyValue = string.Format("{0}:{1}", Name, Argument);
        var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);

        if (value != null)
        {
            controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument;
            isValidName = true;
        }

        return isValidName;
    }
}

면도칼:

<form action="" method="post">
 <input type="submit" value="Save" name="action:Save" />
 <input type="submit" value="Cancel" name="action:Cancel" />
</form>

및 컨트롤러 :

[HttpPost]
[MultipleButton(Name = "action", Argument = "Save")]
public ActionResult Save(MessageModel mm) { ... }

[HttpPost]
[MultipleButton(Name = "action", Argument = "Cancel")]
public ActionResult Cancel(MessageModel mm) { ... }

업데이트 : Razor 페이지기본적으로 동일한 기능을 제공하는 것으로 보입니다. 새로운 개발의 경우 바람직 할 수 있습니다.


제출 버튼에 이름을 지정한 다음 컨트롤러 메서드에서 제출 된 값을 검사합니다.

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="submitButton" value="Send" />
<input type="submit" name="submitButton" value="Cancel" />
<% Html.EndForm(); %>

에 게시

public class MyController : Controller {
    public ActionResult MyAction(string submitButton) {
        switch(submitButton) {
            case "Send":
                // delegate sending to another controller action
                return(Send());
            case "Cancel":
                // call another action to perform the cancellation
                return(Cancel());
            default:
                // If they've submitted the form without a submitButton, 
                // just return the view again.
                return(View());
        }
    }

    private ActionResult Cancel() {
        // process the cancellation request here.
        return(View("Cancelled"));
    }

    private ActionResult Send() {
        // perform the actual send operation here.
        return(View("SendConfirmed"));
    }

}

편집하다:

이 접근 방식을 지역화 된 사이트에서 작동하도록 확장하려면 메시지를 다른 위치에 격리하십시오 (예 : 리소스 파일을 강력한 형식의 리소스 클래스로 컴파일).

그런 다음 코드를 수정하여 다음과 같이 작동하도록합니다.

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="submitButton" value="<%= Html.Encode(Resources.Messages.Send)%>" />
<input type="submit" name="submitButton" value="<%=Html.Encode(Resources.Messages.Cancel)%>" />
<% Html.EndForm(); %>

컨트롤러는 다음과 같아야합니다.

// Note that the localized resources aren't constants, so 
// we can't use a switch statement.

if (submitButton == Resources.Messages.Send) { 
    // delegate sending to another controller action
    return(Send());

} else if (submitButton == Resources.Messages.Cancel) {
     // call another action to perform the cancellation
     return(Cancel());
}

언급 한대로 액션에서 이름을 확인할 수 있지만 이것이 좋은 디자인인지 여부를 고려할 수 있습니다. 작업의 책임을 고려하고이 디자인을 버튼 이름과 같은 UI 측면에 너무 많이 결합하지 않는 것이 좋습니다. 따라서 두 가지 양식과 두 가지 작업을 사용하는 것이 좋습니다.

<% Html.BeginForm("Send", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Send" />
<% Html.EndForm(); %>

<% Html.BeginForm("Cancel", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Cancel" />
<% Html.EndForm(); %>

또한 "취소"의 경우 일반적으로 양식을 처리하지 않고 새 URL로 이동합니다. 이 경우 양식을 전혀 제출할 필요가 없으며 링크 만 있으면됩니다.

<%=Html.ActionLink("Cancel", "List", "MyController") %>

Eilon은 다음과 같이 할 수 있다고 제안합니다.

버튼이 두 개 이상있는 경우 각 버튼에 이름을 지정하여 구분할 수 있습니다.

<input type="submit" name="SaveButton" value="Save data" />
<input type="submit" name="CancelButton" value="Cancel and go back to main page" />

컨트롤러 작업 메서드에서 HTML 입력 태그 이름을 따라 명명 된 매개 변수를 추가 할 수 있습니다.

public ActionResult DoSomeStuff(string saveButton, string
cancelButton, ... other parameters ...)
{ ... }

이러한 매개 변수 중 하나에 값이 게시되면 버튼이 클릭 된 것입니다. 웹 브라우저 는 클릭 된 하나의 버튼에 대한 값만 게시합니다 . 다른 모든 값은 null입니다.

if (saveButton != null) { /* do save logic */ }
if (cancelButton != null) { /* do cancel logic */ }

이 방법은 할당 된 이름보다 변경 될 가능성이 높고 자바 스크립트를 활성화 할 필요가없는 제출 버튼의 값 속성에 의존하지 않기 때문에 좋아합니다.

참조 : http://forums.asp.net/p/1369617/2865166.aspx#2865166


이에 대한 게시물을 작성했습니다. ASP.NET MVC를 사용한 여러 제출 버튼 :

기본적으로, 대신 사용하여 ActionMethodSelectorAttribute내가 사용하고, ActionNameSelectorAttribute나를 액션 이름을 척 할 수있는 것은, 내가이 원하는 모든 것이다. 다행히도 ActionNameSelectorAttribute작업 이름 만 지정하는 것이 아니라 현재 작업이 요청과 일치하는지 여부를 선택할 수 있습니다.

그래서 내 수업이 있습니다 (btw 나는 이름을 너무 좋아하지 않습니다).

public class HttpParamActionAttribute : ActionNameSelectorAttribute {
    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) {
        if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
            return true;

        if (!actionName.Equals("Action", StringComparison.InvariantCultureIgnoreCase))
            return false;

        var request = controllerContext.RequestContext.HttpContext.Request;
        return request[methodInfo.Name] != null;
    }
} 

사용하려면 다음과 같이 양식을 정의하십시오.

<% using (Html.BeginForm("Action", "Post")) { %>
  <!— …form fields… -->
  <input type="submit" name="saveDraft" value="Save Draft" />
  <input type="submit" name="publish" value="Publish" />
<% } %> 

두 가지 방법으로 컨트롤러

public class PostController : Controller {
    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult SaveDraft(…) {
        //…
    }

    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Publish(…) {
        //…
    } 
}

보시다시피 속성은 아무것도 지정하지 않아도됩니다. 또한 버튼 이름은 메서드 이름으로 직접 변환됩니다. 또한 (나는 그것을 시도하지 않았습니다) 이것들은 정상적인 행동으로도 작동해야하므로 직접 게시 할 수 있습니다.


이해 관계자 들이 Maarten Balliauw의 솔루션을 살펴볼 것을 제안 합니다 . 매우 우아하다고 생각합니다.

링크가 사라질 경우 MultiButton컨트롤러 작업에 적용된 속성을 사용하여 해당 작업과 관련된 버튼 클릭을 나타냅니다.


짧고 스위트 :

Jeroen Dop 이 대답했습니다.

<input type="submit" name="submitbutton1" value="submit1" />
<input type="submit" name="submitbutton2" value="submit2" />

코드 비하인드에서 이렇게

 if( Request.Form["submitbutton1"] != null)
{
    // Code for function 1
}
else if(Request.Form["submitButton2"] != null )
{
       // code for function 2
}

행운을 빕니다.


버튼의 이름을 지정하고 값을 지정할 수 있어야합니다. 그런 다음이 이름을 작업에 대한 인수로 매핑합니다. 또는 2 개의 개별 액션 링크 또는 2 개의 양식을 사용합니다.


다음과 같이 작성할 수 있습니다.

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Send" />
<input type="submit" name="button" value="Cancel" />
<% Html.EndForm(); %>

그런 다음 페이지에서 이름 == "보내기"또는 이름 == "취소"인지 확인합니다.


ActionSelectName에서 마음에 들지 않는 점은 IsValidName이 컨트롤러의 모든 작업 메서드에 대해 호출된다는 것입니다. 왜 이런 식으로 작동하는지 모르겠습니다. 나는 모든 버튼이 기능에 따라 다른 이름을 갖는 솔루션을 좋아하지만, 액션 메서드에 폼의 버튼만큼 많은 매개 변수를 가져야한다는 사실이 마음에 들지 않습니다. 모든 버튼 유형에 대한 열거 형을 만들었습니다.

public enum ButtonType
{
    Submit,
    Cancel,
    Delete
}

ActionSelectName 대신 ActionFilter를 사용합니다.

public class MultipleButtonsEnumAttribute : ActionFilterAttribute
{
    public Type EnumType { get; set; }

    public MultipleButtonsEnumAttribute(Type enumType)
    {
        EnumType = enumType;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        foreach (var key in filterContext.HttpContext.Request.Form.AllKeys)
        {
            if (Enum.IsDefined(EnumType, key))
            {
                var pDesc = filterContext.ActionDescriptor.GetParameters()
                    .FirstOrDefault(x => x.ParameterType == EnumType);
                filterContext.ActionParameters[pDesc.ParameterName] = Enum.Parse(EnumType, key);
                break;
            }
        }
    }
}

필터는 양식 데이터에서 버튼 이름을 찾고 버튼 이름이 열거 형에 정의 된 버튼 유형과 일치하는 경우 작업 매개 변수 중에서 ButtonType 매개 변수를 찾습니다.

[MultipleButtonsEnumAttribute(typeof(ButtonType))]
public ActionResult Manage(ButtonType buttonPressed, ManageViewModel model)
{
    if (button == ButtonType.Cancel)
    {
        return RedirectToAction("Index", "Home");
    }
    //and so on
    return View(model)
}

그런 다음 뷰에서 다음을 사용할 수 있습니다.

<input type="submit" value="Button Cancel" name="@ButtonType.Cancel" />
<input type="submit" value="Button Submit" name="@ButtonType.Submit" />

나에게 가장 적합한 방법은 다음과 같습니다.

<input type="submit" value="Delete" name="onDelete" />
<input type="submit" value="Save" name="onSave" />


public ActionResult Practice(MyModel model, string onSave, string onDelete)
{
    if (onDelete != null)
    {
        // Delete the object
        ...
        return EmptyResult();
    }

    // Save the object
    ...
    return EmptyResult();
}

HTML 5 사용에 제한이없는 경우 속성 <button>과 함께 태그를 사용할 수 있습니다 formaction.

<form action="demo_form.asp" method="get">
   First name: <input type="text" name="fname" /><br />
   Last name: <input type="text" name="lname" /><br />
   <button type="submit">Submit</button><br />
   <button type="submit" formaction="demo_admin.asp">Submit as admin</button>
</form>

참조 : http://www.w3schools.com/html5/att_button_formaction.asp


브라우저가 입력 버튼에 대한 속성 formaction을 지원하는 경우 (IE 10+, 다른 브라우저에 대해 확실하지 않음) 다음이 작동합니다.

@using (Html.BeginForm()){
    //put form inputs here

<input id="sendBtn" value="Send" type="submit" formaction="@Url.Action("Name Of Send Action")" />

<input id="cancelBtn" value="Cancel" type="submit" formaction="@Url.Action("Name of Cancel Action") />

}

이 '문제'도 발견했지만 name속성 을 추가하여 다소 논리적 인 해결책을 찾았습니다 . 다른 언어로는이 문제가 있었던 것을 기억할 수 없습니다.

http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2

  • ...
  • 양식에 제출 단추가 두 개 이상 포함 된 경우 활성화 된 제출 단추 만 성공합니다.
  • ...

다음 코드 value속성은 강력한 형식의 리소스 파일이나 상수를 추가로 검사 할 필요 없이 변경, 지역화, 국제화 할 수 있음을 의미합니다 .

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="send" value="Send" />
<input type="submit" name="cancel" value="Cancel" />
<input type="submit" name="draft" value="Save as draft" />
<% Html.EndForm(); %>`

수신 측에서는 알려진 제출 유형이 아닌지 확인하기 만하면됩니다. null

public ActionResult YourAction(YourModel model) {

    if(Request["send"] != null) {

        // we got a send

    }else if(Request["cancel"]) {

        // we got a cancel, but would you really want to post data for this?

    }else if(Request["draft"]) {

        // we got a draft

    }

}

위의 문제를 해결할 수있는 세 가지 방법이 있습니다.

  1. HTML 방식
  2. Jquery 방식
  3. "ActionNameSelectorAttribute"방식

아래는 세 가지 접근 방식을 모두 시연 적으로 요약 한 비디오입니다.

https://www.facebook.com/shivprasad.koirala/videos/vb.100002224977742/809335512483940

HTML 방식 :-

HTML 방식으로 두 개의 양식을 만들고 각 양식 안에 "제출"버튼을 배치해야합니다. 그리고 모든 양식의 작업은 서로 다른 / 각 작업을 가리 킵니다. 아래 코드를 보면 첫 번째 폼이“Action1”에 게시되고 두 번째 폼은“Submit”버튼을 클릭하면“Action2”에 게시됩니다.

<form action="Action1" method=post>
<input type=”submit” name=”Submit1”/>
</form>

<form action="Action2" method=post>
<input type=”submit” name=”Submit2”>
</form>

Ajax 방식 :-

Ajax 애호가라면이 두 번째 옵션이 더 흥분 될 것입니다. Ajax 방식으로 "Fun1"및 "Fun1"두 개의 서로 다른 함수를 만들 수 있습니다. 아래 코드를 참조하십시오. 이러한 함수는 JQUERY 또는 기타 프레임 워크를 사용하여 Ajax 호출을 수행합니다. 이러한 각 기능은 "Submit"버튼의 "OnClick"이벤트와 결합됩니다. 이러한 각 함수는 각 작업 이름을 호출합니다.

<Script language="javascript">
function Fun1()
{
$.post(“/Action1”,null,CallBack1);
}
function Fun2()
{
$.post(“/Action2”,null,CallBack2);
}
</Script>

<form action="/Action1" method=post>
<input type=submit name=sub1 onclick=”Fun2()”/>
</form>
<form action="/Action2" method=post>
<input type=submit name=sub2 onclick=”Fun1()”/>
</form>

"ActionNameSelectorAttribute"사용 :-

이것은 훌륭하고 깨끗한 옵션입니다. "ActionNameSelectorAttribute"는 실행할 수있는 작업을 결정하는 의사 결정 논리를 작성할 수있는 간단한 속성 클래스입니다.

따라서 첫 번째는 HTML에서 서버에서 식별하기 위해 제출 버튼에 적절한 이름을 넣어야한다는 것입니다.

버튼 이름에 "저장"과 "삭제"를 입력 한 것을 볼 수 있습니다. 또한 액션에서 특정 액션 이름이 아닌 컨트롤러 이름 "Customer"를 입력했음을 알 수 있습니다. 액션 이름은“ActionNameSelectorAttribute”에 의해 결정됩니다.

<form action=”Customer” method=post>
<input type=submit value="Save" name="Save" /> <br />
<input type=submit value="Delete" name="Delete"/>
</form>

따라서 제출 버튼을 클릭하면 먼저 "ActionNameSelector"속성에 도달 한 다음 어떤 제출이 실행되었는지에 따라 적절한 작업을 호출합니다.

여기에 이미지 설명 입력

따라서 첫 번째 단계는 "ActionNameSelectorAttribute"클래스에서 상속되는 클래스를 만드는 것입니다. 이 클래스에서 우리는 간단한 속성“Name”을 만들었습니다.

또한 true 또는 flase를 반환하는 "IsValidName"함수를 재정의해야합니다. 이 함수는 동작이 실행되어야하는지 여부에 대한 논리를 작성하는 곳입니다. 따라서이 함수가 true를 반환하면 액션이 실행되거나 실행되지 않습니다.

public class SubmitButtonSelector : ActionNameSelectorAttribute
    {
        public string Name { get; set; }
        public override bool IsValidName(ControllerContext controllerContext, string actionName, System.Reflection.MethodInfo methodInfo)
        {
            // Try to find out if the name exists in the data sent from form
var value = controllerContext.Controller.ValueProvider.GetValue(Name);
            if (value != null)
            {
                return true;
            }
            return false;

        }
    }

위 함수의 핵심은 아래 코드에 있습니다. "ValueProvider"컬렉션에는 양식에서 게시 된 모든 데이터가 있습니다. 따라서 먼저 "이름"값을 조회하고 HTTP 요청에서 찾은 경우 true를 반환하고 그렇지 않으면 false를 반환합니다.

var value = controllerContext.Controller.ValueProvider.GetValue(Name);
if (value != null)
      {
        return true;
      }
      return false;

그런 다음이 속성 클래스를 각 작업에 장식 할 수 있으며 해당 "이름"값을 제공 할 수 있습니다. 따라서 제출이이 조치를 누르고 이름이 HTML 제출 단추 이름과 일치하면 조치를 추가로 실행하거나 그렇지 않으면 수행하지 않습니다.

public class CustomerController : Controller
{
        [SubmitButtonSelector(Name="Save")]
        public ActionResult Save()
        {
            return Content("Save Called");
        }
        [SubmitButtonSelector(Name = "Delete")]
        public ActionResult Delete()
        {
            return Content("Delete Called");
        }
}

David Findley는 ASP.Net 웹 로그에서이 작업을 수행 할 수있는 3 가지 옵션에 대해 씁니다.

그의 솔루션과 각각의 장단점을 보려면 동일한 양식의 여러 버튼 기사를 읽으십시오 . IMHO는 행동을 장식하는 속성을 사용하는 매우 우아한 솔루션을 제공합니다.


이것이 제가 사용할 기술이며 아직 여기에서 볼 수 없습니다. 이 솔루션에 영감을주는 링크 (Saajid Ismail 게시)는 http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form 입니다 . .aspx ). 문제없이 현지화를 수행하기 위해 Dylan Beattie의 답변을 적용합니다.

보기에서 :

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<button name="button" value="send"><%: Resources.Messages.Send %></button>
<button name="button" value="cancel"><%: Resources.Messages.Cancel %></button>
<% Html.EndForm(); %>

컨트롤러에서 :

public class MyController : Controller 
{
    public ActionResult MyAction(string button)
    {
         switch(button)
         {
             case "send":
                 this.DoSend();
                 break;
             case "cancel":
                 this.DoCancel();
                 break;
         }
    }
}

이 스크립트는 모든 브라우저에서 HTML5 formaction 속성으로 작동하는 data-form-action 속성을 지정할 수 있습니다 (간단하게) :

$(document).on('click', '[type="submit"][data-form-action]', function(event) {
    var $this = $(this),
    var formAction = $this.attr('data-form-action'),
    $form = $($this.closest('form'));
    $form.attr('action', formAction);             
});

버튼이 포함 된 양식은 data-form-action 속성에 지정된 URL에 게시됩니다.

<button type="submit" data-form-action="different/url">Submit</button>   

이를 위해서는 jQuery 1.7이 필요합니다. 이전 버전 live()의 경우 on().


다음은 여러 이미지 및 / 또는 텍스트 버튼을 처리하기 위해 작성한 확장 방법입니다.

다음은 이미지 버튼의 HTML입니다.

<input id="btnJoin" name="Join" src="/content/images/buttons/btnJoin.png" 
       type="image">

또는 텍스트 제출 버튼의 경우 :

<input type="submit" class="ui-button green" name="Submit_Join" value="Add to cart"  />
<input type="submit" class="ui-button red" name="Submit_Skip" value="Not today"  />

다음은 컨트롤러에서 호출하는 확장 메서드입니다 form.GetSubmitButtonName(). 이미지 버튼의 경우 .x(이미지 버튼이 클릭되었음을 나타내는) 형식 매개 변수를 찾고 이름을 추출합니다. 일반 input버튼의 경우로 시작하는 이름을 찾고 Submit_나중에 명령을 추출합니다. '명령'을 결정하는 논리를 추상화하고 있기 때문에 서버 측 코드를 변경하지 않고도 클라이언트의 이미지 + 텍스트 버튼간에 전환 할 수 있습니다.

public static class FormCollectionExtensions
{
    public static string GetSubmitButtonName(this FormCollection formCollection)
    {
        return GetSubmitButtonName(formCollection, true);
    }

    public static string GetSubmitButtonName(this FormCollection formCollection, bool throwOnError)
    {
        var imageButton = formCollection.Keys.OfType<string>().Where(x => x.EndsWith(".x")).SingleOrDefault();
        var textButton = formCollection.Keys.OfType<string>().Where(x => x.StartsWith("Submit_")).SingleOrDefault();

        if (textButton != null)
        {
            return textButton.Substring("Submit_".Length);
        }

        // we got something like AddToCart.x
        if (imageButton != null)
        {
            return imageButton.Substring(0, imageButton.Length - 2);
        }

        if (throwOnError)
        {
            throw new ApplicationException("No button found");
        }
        else
        {
            return null;
        }
    }
}

참고 : 텍스트 버튼의 경우 이름 앞에 Submit_. 코드를 변경하지 않고도 텍스트 (디스플레이) 값을 변경할 수 있기 때문에이 방식을 선호합니다. SELECT요소 와 달리 INPUT버튼에는 '값'만 있고 별도의 '텍스트'속성이 없습니다. 내 버튼은 상황에 따라 다르게 말하지만 동일한 '명령'에 매핑됩니다. 나는 코드를 작성하는 것보다 이런 방식으로 이름을 추출하는 것을 선호합니다 == "Add to cart".


정확한 위치에 댓글을 달 수있는 담당자가 충분하지 않지만 하루 종일이 일을 보냈으므로 공유하고 싶습니다.

"MultipleButtonAttribute"솔루션을 구현하는 동안 ValueProvider.GetValue(keyValue)잘못 돌아올 것 null입니다.

4.0이어야 할 때 System.Web.MVC 버전 3.0을 참조하는 것으로 나타났습니다 (다른 어셈블리는 4.0입니다). 내 프로젝트가 제대로 업그레이드되지 않은 이유를 모르겠고 다른 명백한 문제가 없었습니다.

따라서 ActionNameSelectorAttribute작동하지 않는 경우 ... 확인하십시오.


나는 파티에 꽤 늦었지만 여기에 간다 ... 내 구현은 @mkozicki에서 빌려 왔지만 잘못되기 위해 덜 하드 코딩 된 문자열이 필요합니다. Framework 4.5 이상이 필요합니다 . 기본적으로 컨트롤러 메서드 이름은 라우팅의 키가되어야합니다.

마크 업 . 버튼 이름은 다음과 같이 입력해야합니다."action:[controllerMethodName]"

(C # 6 nameof API를 사용하여 호출하려는 컨트롤러 메서드의 이름에 대한 유형별 참조를 제공합니다.

<form>
    ... form fields ....
    <button name="action:@nameof(MyApp.Controllers.MyController.FundDeathStar)" type="submit" formmethod="post">Fund Death Star</button>
    <button name="action:@nameof(MyApp.Controllers.MyController.HireBoba)" type="submit" formmethod="post">Hire Boba Fett</button>
</form>

컨트롤러 :

namespace MyApp.Controllers
{
    class MyController
    {    
        [SubmitActionToThisMethod]
        public async Task<ActionResult> FundDeathStar(ImperialModel model)
        {
            await TrainStormTroopers();
            return View();
        }

        [SubmitActionToThisMethod]
        public async Task<ActionResult> HireBoba(ImperialModel model)
        {
            await RepairSlave1();
            return View();
        }
    }
}

속성 매직 . CallerMemberName선함 의 사용에 주목하십시오 .

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class SubmitActionToThisMethodAttribute : ActionNameSelectorAttribute
{        
    public SubmitActionToThisMethodAttribute([CallerMemberName]string ControllerMethodName = "")
    {
        controllerMethod = ControllerMethodName;
        actionFormat = string.Concat(actionConstant, ":", controllerMethod);
    }
    const string actionConstant = "action";
    readonly string actionFormat;
    readonly string controllerMethod;

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        var isValidName = false;
        var value = controllerContext.Controller.ValueProvider.GetValue(actionFormat);

        if (value != null)
        {
            controllerContext.Controller.ControllerContext.RouteData.Values[actionConstant] = controllerMethod;
            isValidName = true;
        }
        return isValidName;
    }
}

저는 모든 솔루션을 통합하려고 노력했고 폼에서 여러 버튼을 쉽게 처리 할 수있는 [ButtenHandler] 속성을 만들었습니다.

ASP.NET MVC의 CodeProject Multiple 매개 변수화 (지역화 가능) 양식 단추에 대해 설명했습니다 .

이 버튼의 간단한 경우를 처리하려면 :

<button type="submit" name="AddDepartment">Add Department</button>

다음과 같은 작업 방법이 있습니다.

[ButtonHandler()]
public ActionResult AddDepartment(Company model)
{
    model.Departments.Add(new Department());
    return View(model);
}

버튼의 이름이 액션 메서드의 이름과 어떻게 일치하는지 확인하십시오. 이 기사에서는 값이있는 버튼과 인덱스가있는 버튼을 사용하는 방법도 설명합니다.


//model
    public class input_element
        {
         public string Btn { get; set; }
        }   

//views--submit btn can be input type also...
    @using (Html.BeginForm())
    {
            <button type="submit" name="btn" value="verify">
             Verify data</button>
            <button type="submit" name="btn" value="save">
             Save data</button>    
            <button type="submit" name="btn" value="redirect">
                 Redirect</button>
    }

//controller

    public ActionResult About()
        {
            ViewBag.Message = "Your app description page.";
            return View();
        }

        [HttpPost]
        public ActionResult About(input_element model)
        {
                if (model.Btn == "verify")
                {
                // the Verify button was clicked
                }
                else if (model.Btn == "save")
                {
                // the Save button was clicked
                } 
                else if (model.Btn == "redirect")
                {
                // the Redirect button was clicked
                } 
                return View();
        }

이것이 내가 찾은 가장 좋은 방법입니다.

http://iwayneo.blogspot.co.uk/2013/10/aspnet-mvc-action-selector-with-list.html

다음은 코드입니다.

    /// <summary>
    /// ActionMethodSelector to enable submit buttons to execute specific action methods.
    /// </summary>
    public class AcceptParameterAttribute : ActionMethodSelectorAttribute
   {
        /// <summary>
        /// Gets or sets the value to use to inject the index into
        /// </summary>
       public string TargetArgument { get; set; }

       /// <summary>
       /// Gets or sets the value to use in submit button to identify which method to select. This must be unique in each controller.
       /// </summary>
       public string Action { get; set; }

       /// <summary>
       /// Gets or sets the regular expression to match the action.
       /// </summary>
       public string ActionRegex { get; set; }

       /// <summary>
       /// Determines whether the action method selection is valid for the specified controller context.
       /// </summary>
       /// <param name="controllerContext">The controller context.</param>
       /// <param name="methodInfo">Information about the action method.</param>
       /// <returns>true if the action method selection is valid for the specified controller context; otherwise, false.</returns>
       public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
       {

           if (controllerContext == null)
           {
               throw new ArgumentNullException("controllerContext");
           }

           Func<NameValueCollection> formGetter;
           Func<NameValueCollection> queryStringGetter;

           ValidationUtility.GetUnvalidatedCollections(HttpContext.Current, out formGetter, out queryStringGetter);

           var form = formGetter();
           var queryString = queryStringGetter();

           var req = form.AllKeys.Any() ? form : queryString;

           if (!string.IsNullOrEmpty(this.ActionRegex))
           {
               foreach (var key in req.AllKeys.Where(k => k.StartsWith(Action, true, System.Threading.Thread.CurrentThread.CurrentCulture)))
               {
                   if (key.Contains(":"))
                   {
                       if (key.Split(':').Count() == this.ActionRegex.Split(':').Count())
                       {
                           bool match = false;
                           for (int i = 0; i < key.Split(':').Count(); i++)
                           {
                               if (Regex.IsMatch(key.Split(':')[0], this.ActionRegex.Split(':')[0]))
                               {
                                   match = true;
                               }
                               else
                               {
                                   match = false;
                                   break;
                               }
                           }

                           if (match)
                           {
                               return !string.IsNullOrEmpty(req[key]);
                           }
                       }
                   }
                   else
                   {
                       if (Regex.IsMatch(key, this.Action + this.ActionRegex))
                       {
                           return !string.IsNullOrEmpty(req[key]);
                       }
                   }

               }
               return false;
           }
           else
           {
               return req.AllKeys.Contains(this.Action);
           }
       }
   }

코드 냄새가없는 다중 제출 버튼 미래를 즐기십시오.

감사합니다


[HttpPost]
public ActionResult ConfirmMobile(string nameValueResend, string nameValueSubmit, RegisterModel model)
    {
        var button = nameValueResend ?? nameValueSubmit;
        if (button == "Resend")
        {

        }
        else
        {

        }
    }


    Razor file Content:
    @using (Html.BeginForm()
    {
        <div class="page registration-result-page">

            <div class="page-title">
                <h1> Confirm Mobile Number</h1>
            </div>

            <div class="result">
                @Html.EditorFor(model => model.VefificationCode)
                @Html.LabelFor(model => model.VefificationCode, new { })
                @Html.ValidationMessageFor(model => model.VefificationCode)
            </div>
            <div class="buttons">
                <button type="submit" class="btn" name="nameValueResend" value="Resend">
                    Resend
                </button>
                <button type="submit" class="btn" name="nameValueSubmit" value="Verify">
                    Submit
                </button>

            </div>
            </div>

    }

HttpParamActionAttribute메서드의 수정 된 버전 이지만 만료 / 유효하지 않은 세션 포스트 백에 오류를 일으키지 않는 버그 수정이 있습니다. 이 현재 사이트에 문제가있는 경우 창에서 양식을 열고 당신이 클릭로 이동하기 전에 확인하려면 Save또는 Publish중복 창 및 로그 아웃을 엽니 다. 이제 첫 번째 창으로 돌아가서 두 버튼 중 하나를 사용하여 양식을 제출해보십시오. 나를 위해 오류가 발생 하여이 변경으로 해당 문제가 해결됩니다. 간결함을 위해 많은 것을 생략했지만 아이디어를 얻어야합니다. 핵심 부분은 ActionName속성에 포함 하고 전달 된 이름이 양식을 표시하는보기의 이름인지 확인하는 것입니다.

속성 클래스

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class HttpParamActionAttribute : ActionNameSelectorAttribute
{
    private readonly string actionName;

    public HttpParamActionAttribute(string actionName)
    {
        this.actionName = actionName;
    }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
            return true;

        if (!actionName.Equals(this.actionName, StringComparison.InvariantCultureIgnoreCase))
            return false;

        var request = controllerContext.RequestContext.HttpContext.Request;
        return request[methodInfo.Name] != null;
    }
}

제어 장치

[Authorize(Roles="CanAddContent")]
public ActionResult CreateContent(Guid contentOwnerId)
{
    var viewModel = new ContentViewModel
    {
        ContentOwnerId = contentOwnerId
        //populate rest of view model
    }
    return View("CreateContent", viewModel);
}

[Authorize(Roles="CanAddContent"), HttpPost, HttpParamAction("CreateContent"), ValidateAntiForgeryToken]
public ActionResult SaveDraft(ContentFormModel model)
{
    //Save as draft
    return RedirectToAction("CreateContent");
}

[Authorize(Roles="CanAddContent"), HttpPost, HttpParamAction("CreateContent"), ValidateAntiForgeryToken]
public ActionResult Publish(ContentFormModel model)
{
    //publish content
    return RedirectToAction("CreateContent");
}

전망

@using (Ajax.BeginForm("CreateContent", "MyController", new { contentOwnerId = Model.ContentOwnerId }))
{
    @Html.AntiForgeryToken()
    @Html.HiddenFor(x => x.ContentOwnerId)

    <!-- Rest of your form controls -->
    <input name="SaveDraft" type="submit" value="SaveDraft" />
    <input name="Publish" type="submit" value="Publish" />
}

확장 방법을 사용하는 내 JQuery 접근 방식 :

public static MvcHtmlString SubmitButtonFor<TController>(this HtmlHelper helper, Expression<Action<TController>> action, string value) where TController : Controller
{
    RouteValueDictionary routingValues = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression(action);

    var onclick = string.Format("$('form').first().attr('action', '/{0}')", string.Join("/", routingValues.Values.ToArray().Where(x => x != null).Select(x => x.ToString()).ToArray()));
    var html = "<input type=\"submit\" value=\"" + value + "\" onclick=\"" + onclick + "\" />";

    return MvcHtmlString.Create(html);
}

다음과 같이 사용할 수 있습니다.

@(Html.SubmitButtonFor<FooController>(c => c.Save(null), "Save"))

그리고 다음과 같이 렌더링됩니다.

<input type="submit" value="Save" onclick="$('form').first().attr('action', '/Foo/Save')" >

각 제출 버튼에 대해 다음을 추가하십시오.

$('#btnSelector').click(function () {

    $('form').attr('action', "/Your/Action/);
    $('form').submit();

});

mkozicki 답변에 따라 약간 다른 솔루션을 생각해 냈습니다. 여전히 사용하고 ActionNameSelectorAttribute있지만 '저장'과 '동기화'버튼 두 개를 처리해야했습니다. 그들은 거의 똑같은 일을하므로 두 가지 행동을하고 싶지 않았습니다.

속성 :

public class MultipleButtonActionAttribute : ActionNameSelectorAttribute
{        
    private readonly List<string> AcceptedButtonNames;

    public MultipleButtonActionAttribute(params string[] acceptedButtonNames)
    {
        AcceptedButtonNames = acceptedButtonNames.ToList();
    }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {            
        foreach (var acceptedButtonName in AcceptedButtonNames)
        {
            var button = controllerContext.Controller.ValueProvider.GetValue(acceptedButtonName);
            if (button == null)
            {
                continue;
            }                
            controllerContext.Controller.ControllerContext.RouteData.Values.Add("ButtonName", acceptedButtonName);
            return true;
        }
        return false;
    }
}

전망

<input type="submit" value="Save" name="Save" />
<input type="submit" value="Save and Sync" name="Sync" />

제어 장치

 [MultipleButtonAction("Save", "Sync")]
 public ActionResult Sync(OrgSynchronizationEditModel model)
 {
     var btn = this.RouteData.Values["ButtonName"];

나는 또한 행동이 다른 일을한다면 아마도 mkozicki post를 따를 것이라고 지적하고 싶습니다.


HtmlHelper에 대한 ActionButton 메서드를 만들었습니다 . OnClick 이벤트 에서 약간의 자바 스크립트 가 포함 된 일반 입력 버튼을 생성 하여 지정된 컨트롤러 / 액션에 양식을 제출합니다.

당신은 그런 도우미를 사용합니다

@Html.ActionButton("MyControllerName", "MyActionName", "button text")

그러면 다음 HTML이 생성됩니다.

<input type="button" value="button text" onclick="this.form.action = '/MyWebsiteFolder/MyControllerName/MyActionName'; this.form.submit();">

확장 메서드 코드는 다음과 같습니다.

VB.Net

<System.Runtime.CompilerServices.Extension()>
Function ActionButton(pHtml As HtmlHelper, pAction As String, pController As String, pRouteValues As Object, pBtnValue As String, pBtnName As String, pBtnID As String) As MvcHtmlString
    Dim urlHelperForActionLink As UrlHelper
    Dim btnTagBuilder As TagBuilder

    Dim actionLink As String
    Dim onClickEventJavascript As String

    urlHelperForActionLink = New UrlHelper(pHtml.ViewContext.RequestContext)
    If pController <> "" Then
        actionLink = urlHelperForActionLink.Action(pAction, pController, pRouteValues)
    Else
        actionLink = urlHelperForActionLink.Action(pAction, pRouteValues)
    End If
    onClickEventJavascript = "this.form.action = '" & actionLink & "'; this.form.submit();"

    btnTagBuilder = New TagBuilder("input")
    btnTagBuilder.MergeAttribute("type", "button")

    btnTagBuilder.MergeAttribute("onClick", onClickEventJavascript)

    If pBtnValue <> "" Then btnTagBuilder.MergeAttribute("value", pBtnValue)
    If pBtnName <> "" Then btnTagBuilder.MergeAttribute("name", pBtnName)
    If pBtnID <> "" Then btnTagBuilder.MergeAttribute("id", pBtnID)

    Return MvcHtmlString.Create(btnTagBuilder.ToString(TagRenderMode.Normal))
End Function

C # (C # 코드는 VB DLL에서 디 컴파일되었으므로 약간의 미화를 얻을 수 있지만 시간이 너무 짧습니다 :-))

public static MvcHtmlString ActionButton(this HtmlHelper pHtml, string pAction, string pController, object pRouteValues, string pBtnValue, string pBtnName, string pBtnID)
{
    UrlHelper urlHelperForActionLink = new UrlHelper(pHtml.ViewContext.RequestContext);
    bool flag = Operators.CompareString(pController, "", true) != 0;
    string actionLink;
    if (flag)
    {
        actionLink = urlHelperForActionLink.Action(pAction, pController, System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(pRouteValues));
    }
    else
    {
        actionLink = urlHelperForActionLink.Action(pAction, System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(pRouteValues));
    }
    string onClickEventJavascript = "this.form.action = '" + actionLink + "'; this.form.submit();";
    TagBuilder btnTagBuilder = new TagBuilder("input");
    btnTagBuilder.MergeAttribute("type", "button");
    btnTagBuilder.MergeAttribute("onClick", onClickEventJavascript);
    flag = (Operators.CompareString(pBtnValue, "", true) != 0);
    if (flag)
    {
        btnTagBuilder.MergeAttribute("value", pBtnValue);
    }
    flag = (Operators.CompareString(pBtnName, "", true) != 0);
    if (flag)
    {
        btnTagBuilder.MergeAttribute("name", pBtnName);
    }
    flag = (Operators.CompareString(pBtnID, "", true) != 0);
    if (flag)
    {
        btnTagBuilder.MergeAttribute("id", pBtnID);
    }
    return MvcHtmlString.Create(btnTagBuilder.ToString(TagRenderMode.Normal));
}

이러한 메서드에는 다양한 매개 변수가 있지만 사용하기 쉽도록 필요한 매개 변수 만 사용하는 오버로드를 만들 수 있습니다.

참고 URL : https://stackoverflow.com/questions/442704/how-do-you-handle-multiple-submit-buttons-in-asp-net-mvc-framework

반응형