1
votes

I am currently learning ASP.NET MVC and I have been given a task to create a website where the user can upload a file to.

I have written the following FileUploadingController as an API which when I try to call via a form in my view for my website I get the following error: 'The controller for path '/api/FileUploading/UploadFile' was not found or does not implement IController.'

This is my API for uploading the users file.

public class FileUploadingController : ApiController
{
    [HttpPost]
    [Route("api/FileUploading/UploadFile")]
    public async Task<string> UploadFile()
    {
        var ctx = HttpContext.Current;
        var root = ctx.Server.MapPath("~/App_Data");
        var provider =
            new MultipartFormDataStreamProvider(root);

        try
        {
            await Request.Content
                .ReadAsMultipartAsync(provider);

            foreach (var file in provider.FileData)
            {
                var name = file.Headers
                    .ContentDisposition
                    .FileName;

                // remove double quotes from string.
                name = name.Trim('"');

                var localFileName = file.LocalFileName;
                var filePath = Path.Combine(root, name);

                File.Move(localFileName, filePath);
            }
        }
        catch (Exception e)
        {
            return $"Error: {e.Message}";
        }

        return "File uploaded!";
    }
}

And here is my form which calls this API.

<form 
    method ="post"
    enctype="multipart/form-data"
    action="https://localhost:44327/api/FileUploading/UploadFile"   
>            
    <div>
        <label for="img">Image File</label>
        <input name="img" type="file"/>
    </div>
    <div>
        <input type="submit" value="upload" />
</div>
</form>

While I am aware this method is not the best way to do it and have discussed with my tutor about alternative methods, neither of us can work out why this error is happening (I do understand what the error means but I am stumped as how to resolve it without taking a different approach), albeit we didn't look for too long.

Thanks!

EDIT: As per requested here is the contents of my WebApiConfig.cs

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}
3
@Could it be that you're trying to post a form but the endpoint you're trying to hit doesn't have any parameters? Like [FormBody] for example. ASP.NET might not know how to route to that action in your controller. - nick gowdy
Your route should be "https://localhost:44327/FileUploading/api/FileUploading/UploadFile" You forgot the controller name - Train
@Train if I put the route in like you have suggested I get a Error 404 - K Emery
@nickgowdy I'm not sure I understand what you mean by this, would you please be able to clarify? - K Emery
What code do you have in the WebApiConfig.cs file in the App_Start folder? - Steve

3 Answers

1
votes

If you are using attribute routing than you can't use the conventional(route template) routing.

Remove below and it should work:

 config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

The documentation says you can combine two but here is one github issue that says otherwise.

1
votes

We resolved the issue by adding

GlobalConfiguration.Configure(WebApiConfig.Register);

To the Global.asax.cs file.

0
votes

You don't return any response. That way your client thinks that the controller doesn't exist. Just return an ActionResult. That should do the trick.

    public class FileUploadingController : ApiController
{
    [HttpPost]
    [Route("api/FileUploading/UploadFile")]
    public async Task<ActionResult> UploadFile()
    {
        var ctx = HttpContext.Current;
        var root = ctx.Server.MapPath("~/App_Data");
        var provider =
            new MultipartFormDataStreamProvider(root);

        try
        {
            await Request.Content
                .ReadAsMultipartAsync(provider);

            foreach (var file in provider.FileData)
            {
                var name = file.Headers
                    .ContentDisposition
                    .FileName;

                // remove double quotes from string.
                name = name.Trim('"');

                var localFileName = file.LocalFileName;
                var filePath = Path.Combine(root, name);

                File.Move(localFileName, filePath);
            }
        }
        catch (Exception e)
        {
            return $"Error: {e.Message}";
        }

        return Ok("File uploaded!"); //or return Content("File uploaded!")
    }
}