locked
Problem to calling the controller from view RRS feed

  • Question

  • User887623398 posted

    Hello,

    Is this URI for Axios correct to call the controller:

    const res = await axios.post("WeatherForecast/post", FormData);

    Here comes the view and the controller:

    import React, { useState } from "react";
    import axios from "axios";
    
    
    export  const FileUpload = () => {
    
        
    
            const [file, setFile] = useState();
            const [fileName, setFileName] = useState();
    
            const SaveFile = (e) => {
    
                console.log(e.target.files[0]);
                setFile(e.target.files[0]);
                setFileName(e.target.files[0].name);
    
        };
    
        const UploadFile = async (e) => {
            console.log(file);
            const formData = new FormData();
            formData.append("formFile", file);
            formData.append("fileName", fileName);
    
            try {
                const res = await axios.post("WeatherForecast/post", FormData);
                  
                
                console.log(res);
    
            } catch (ex) {
                console.log(ex);
            }
        };
    
        return (
            <>
                <input type="file" onChange={SaveFile} />
                <input type="button" value="upload" onClick={UploadFile} />
            </>
    
            );
    
        
    };
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Logging;
    
    namespace imageEditor3.Controllers
    {
        [Route("WeatherForecast")]
    
        [ApiController]
    
        public class WeatherForecastController : ControllerBase
        {
            private static readonly string[] Summaries = new[]
            {
                "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
            };
    
            private readonly ILogger<WeatherForecastController> _logger;
    
            public WeatherForecastController(ILogger<WeatherForecastController> logger)
            {
                _logger = logger;
            }
            [Route("WeatherForecast/post")]
            [HttpPost]
            public IActionResult Post([FromForm] FileModel file)
            {
                try
                {
                    string path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", file.FileName);
    
                    using (Stream stream = new FileStream(path, FileMode.Create))
                    {
    
                        file.FormFile.CopyTo(stream);
    
                    }
    
                    return StatusCode(StatusCodes.Status201Created);
    
                }
    
                catch (Exception)
                {
                    return StatusCode(StatusCodes.Status500InternalServerError);
                }
            }
    
    
    
            [HttpGet]
            public IEnumerable<WeatherForecast> Get()
            {
                var rng = new Random();
                return Enumerable.Range(1, 5).Select(index => new WeatherForecast
                {
                    Date = DateTime.Now.AddDays(index),
                    TemperatureC = rng.Next(-20, 55),
                    Summary = Summaries[rng.Next(Summaries.Length)]
                })
                .ToArray();
            }
        }
    }
    

    If yes, why I can't upload an image?

    Saturday, January 9, 2021 6:39 AM

Answers

  • User475983607 posted

    But why we need to write it twice?

    Because you specifically and openly coded the route to require two WeatherForecast parts in the URL!  See the official routing documentation to learn the basics.  https://docs.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

    Your controller route.

        [Route("WeatherForecast")]
        [ApiController]
        public class WeatherForecastController : ControllerBase
        {

    Your action route.

            [Route("WeatherForecast/post")]
            [HttpPost]
            public IActionResult Post([FromForm] FileModel file)
            {

    I think it is worth mentioning, the "post" route part goes against standard REST patterns  The HTTP method (GET, POST, PUT,...) should be used to select the action.  Any beginning level Web API tutorial will cover standard REST programming patterns.  It would do a lot of good to go through the tutorials on this sites rather than making up your custom REST patterns.

    https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api?view=aspnetcore-5.0&tabs=visual-studio

    Anyway, your action can be changed to the following.

    [HttpPost] 
    public IActionResult Post([FromForm] FileModel file) {

    The URL becomes "WeatherForecast" and the HTTP "POST" selects the appropriate method.  

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, January 10, 2021 5:08 PM

All replies

  • User-474980206 posted

    you shouldn't double post.

    you have a typo in the ajax post. you are passing the FormData, not formData. also the url is wrong. as the controller has the route WeatherForecast, its there twice:

               const res = await axios.post("WeatherForecast/WeatherForecast/post", formData);
    Saturday, January 9, 2021 5:44 PM
  • User887623398 posted

    I changed the URI. But still can't call the back end.

     const UploadFile = async (e) => {
            console.log(file);
            const formData = new FormData();
            formData.append("formFile", file);
            formData.append("fileName", fileName);
    
            try {
                const res = await axios.post("WeatherForecast/WeatherForecast/post", formData);
                  
                
                console.log(res);
    
            } catch (ex) {
                console.log(ex);
            }

    Even I can't see the log file.

    Can it be due to the "MapControllerRoot"?

    app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllerRoute(
                        name: "default",
                        pattern: "{controller=WeatherForecast}/{action=Index}/{id?}");
    
    
                });

    Saturday, January 9, 2021 8:54 PM
  • User-474980206 posted

    I added your sample code to an app created with

        dotnet new react

    project and with the one change it worked fine (well the file write in the controller  failed until I created a wwwroot folder.)

    Saturday, January 9, 2021 10:09 PM
  • User887623398 posted

    Yes, this link works

     const res = await axios.post("WeatherForecast/WeatherForecast/post", formData);

    But why we need to write it twice?

    thanks,

    Saturday, January 9, 2021 11:05 PM
  • User-474980206 posted

    Read documentation on route attributes. You have specified a base route for the controller and additional route paths for the actions

    Sunday, January 10, 2021 5:01 PM
  • User475983607 posted

    But why we need to write it twice?

    Because you specifically and openly coded the route to require two WeatherForecast parts in the URL!  See the official routing documentation to learn the basics.  https://docs.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

    Your controller route.

        [Route("WeatherForecast")]
        [ApiController]
        public class WeatherForecastController : ControllerBase
        {

    Your action route.

            [Route("WeatherForecast/post")]
            [HttpPost]
            public IActionResult Post([FromForm] FileModel file)
            {

    I think it is worth mentioning, the "post" route part goes against standard REST patterns  The HTTP method (GET, POST, PUT,...) should be used to select the action.  Any beginning level Web API tutorial will cover standard REST programming patterns.  It would do a lot of good to go through the tutorials on this sites rather than making up your custom REST patterns.

    https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api?view=aspnetcore-5.0&tabs=visual-studio

    Anyway, your action can be changed to the following.

    [HttpPost] 
    public IActionResult Post([FromForm] FileModel file) {

    The URL becomes "WeatherForecast" and the HTTP "POST" selects the appropriate method.  

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, January 10, 2021 5:08 PM
  • User887623398 posted

    Thanks a lot for your help and supports.

    But if I want to bind a component, for example, an image editor or a grid, to a model, which HTTP request should I use?

    Post, Get, Put, Delete?

    Sunday, January 10, 2021 7:45 PM
  • User475983607 posted

    SaeedP

    But if I want to bind a component, for example, an image editor or a grid, to a model, which HTTP request should I use?

    Post, Get, Put, Delete?

    Um yeah, these fundamentals are openly covered in the tutorials.   I think you'll be interested in clicking the link(s) above and reading.

    • GET - Gets an item.
    • POST - Saves a new item.
    • PUT - Update an item.
    • DELETE - Delete an item.
    Sunday, January 10, 2021 8:12 PM
  • User-474980206 posted

    you really should read a tutorial about coding before starting.

    reading any tutorial on REST would cover this.

        https://restfulapi.net

    REST implements CRUD

      Create = post method
      Read = get method
      Update = put method
      Delete = delete method

    any beginning tutorial on webapi, would tell you that you name the actions after the method for default mapping

      https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api?view=aspnetcore-5.0&tabs=visual-studio

    you should also understand the importance of idempotence. this is key to a reliable REST api.

      https://restfulapi.net/idempotent-rest-apis/

    Sunday, January 10, 2021 8:15 PM