ajaxasp.net-core.net-6.0optimizely

Make a POST request to Non controller method using AJAX in .NET 6


Below Ajax call is not invoking the Non controller method(Index) in .NET core 6.

 $.ajax({
    type: 'POST',
    contentType: false,
    processData: false,
    url: form.action,
    data: formData,
    success: () => {
    },
    error: () => {   
    }});


Html :

<form method="POST" enctype="multipart/form-data">
    @Html.AntiForgeryToken()
    
    <div>
    
    --------
    ----
    --
    </div>

    <div class="btns">
        <button class="fill reset-button" type="button">@Html.PropertyFor(model => model.ResetButtonText)</button>
        <button class="fill send-button" type="button" this.disabled="true">@Html.PropertyFor(model => model.SendButtonText)</button>
    </div>
    <br />
    <div class="se">
        <div class="alert alert-info" style="display:none">Sending...</div>
        <div class="alert alert-danger" style="display:none">There was an issue with the submitted data. Please correct any errors and resubmit.</div>
        <div class="alert alert-success" style="display: none">Your message was sent successfully.</div>
    </div>
</form>

Method :

 [HttpPost]
    [ValidateAntiForgeryToken]
    public IViewComponentResult Index(Block currentContent, ViewModel viewModel)
    {
    //code
    }

Hardcoded the url , still it is not invoking the Index method . Ajax call should invoke Index method which is not part of Controllers folder.


Solution

  • In .NET Core, ViewComponent is not accessed through traditional controller routing. It is usually called through the @Component.InvokeAsync method in the view or page View components.

    If you want to submit to the corresponding URL endpoint using ajax, you can submit to a method inherited from controller, call the view component in it, pass currentContent and viewModel and return the result of the view component. Here is an example for your referenceļ¼š

    First, I configured a corresponding method in a controller to correspond to the ajax endpoint URL and data, and then called the component named home1 that I created:

    Homecontroller:
    public class HomeController : Controller
    {
      [HttpPost]
      [ValidateAntiForgeryToken]
      public IActionResult InvokeHome1Component(Block currentContent, ViewModel viewModel)
      {
          var result = ViewComponent("Home1", new { currentContent, viewModel });
          return result;
      }
    }
    

    Home1ViewComponent :

    public class Home1ViewComponent : ViewComponent
    {
        [HttpPost]
        [ValidateAntiForgeryToken]
        public IViewComponentResult Invoke(Block currentContent, ViewModel viewModel)
        {
                
            return View(viewModel);
        }
    }
    

    I configured the relevant component view in the path Views\Home\Components\Home1\Default.cshtml :

    @model ViewModel
    
    <div>
        <h1>@Model.ResetButtonText</h1>
        <h1>@Model.SendButtonText</h1>
    </div>
    

    Ajax submits the corresponding URL endpoint. And I configured the update page content in the success callback and presented it in <div id="viewComponentContainer"></div>:

    @model ViewModel
    
    <form method="POST" enctype="multipart/form-data" >
        @Html.AntiForgeryToken()
    
        <div>
           
        </div>
    
        <div class="btns">
            <button class="fill reset-button" type="button">@Html.DisplayFor(model => model.ResetButtonText)</button>
            <button class="fill send-button" type="submit">@Html.DisplayFor(model => model.SendButtonText)</button>
        </div>
        <br />
        <div class="se">
            <div class="alert alert-info" style="display:none">Sending...</div>
            <div class="alert alert-danger" style="display:none">There was an issue with the submitted data. Please correct any errors and resubmit.</div>
            <div class="alert alert-success" style="display: none">Your message was sent successfully.</div>
        </div>
    </form>
    
    <div id="viewComponentContainer"></div>
    
    @section scripts {
        <script>
            $(document).ready(function () {
                $('form').on('submit', function (event) {
                    event.preventDefault();
                    var form = this;
                    var formData = new FormData(form);
                    formData.append('currentContent', 'exampleContent');
                    formData.append('viewModel.ResetButtonText', 'Reset');
                    formData.append('viewModel.SendButtonText', 'Send');
    
                    $.ajax({
                        type: 'POST',
                        contentType: false,
                        processData: false,
                        url: '/Home/InvokeHome1Component',
                        data: formData,
                        success: function (response) {
                            $('#viewComponentContainer').html(response);
                            $('.alert-info').hide();
                            $('.alert-success').show();
                        },
                        error: function () {
                            $('.alert-info').hide();
                            $('.alert-danger').show();
                        },
                        beforeSend: function () {
                            $('.alert-info').show();
                        }
                    });
                });
            });
        </script>
    }
    

    When I click the submit button, the data will first be submitted to my controller method: enter image description here

    and then passed to my view component: enter image description here

    Finally, the component update is completed and loaded in my view:

    enter image description here

    Update:

    After my test, when the parameter name in the model is the same as the model parameter name received in the method, the data cannot be received in the controller, such as:

    public class Block
    {
         public int? Id { get; set; }
         public string? currentContent { get; set; }
    
    }
    

    enter image description here

    This will cause the model binding to fail. Therefore, to avoid this error, you need to avoid encountering the same name, such as changing the parameter name in the model:

    public class Block
    {
        public int? Id { get; set; }
        public string? Content { get; set; }  
    }
    
      public class ViewModel
      {
            
          public string? ResetButtonText { get; set; }
          public string? SendButtonText { get; set; }
      }
    

    ajax:

    formData.append('Content', 'exampleContent');
    formData.append('viewModel.ResetButtonText', 'Reset');
    formData.append('viewModel.SendButtonText', 'Send');
    

    When passing data again enter image description here enter image description here