3

I've been looking through questions on SO all day but I feel like I'm not getting anywhere here so I turn to the community. Hope you clever folks can help me out. I've got the following controller action in my project:

[HttpGet("export")]
public IActionResult ExportData(string exportType, DateTime? fromDate, DateTime toDate, string search, bool? locked)
{
    // Load the data from the db.
    var data = LoadData(fromDate, toDate, locked, search);
    bytes[] contentBytes = new byte[] { };
    switch (exportType)
    {
        case "csv":
           contentBytes = DataHelpers.ExportDataToCSV(data);
           break;
        // Other cases removed for brevity.
    }
    var content = new MemoryStream(contentBytes);
    return File(content, MediaTypeNames.Application.Octet, "Report.csv");
}

I'm honestly not sure if the export works because I keep getting an HTTP 404 on my ajax query to it:

function dataExport(type) {
    const search = document.getElementById("GridSearch").value;
    const fromDate = document.getElementById("startDate").value;
    const toDate = document.getElementById("endDate").value;
    const locked = document.getElementById("LockedStatus").checked;

    let args = "?exportType=" + type + "&";
    if (search !== null && search.length >= 1) {
        args += "search=" + search + "&";
    }
    if (fromDate !== null && fromDate.length >= 1) {
        args += "fromDate=" + fromDate + "&";
    }
    if (toDate !== null && toDate.length >= 1) {
        args += "toDate=" + toDate + "&";
    }
    if (locked === true || locked === false) {
        args += "locked=" + locked
    }

    if (args.endsWith("&")) {
        args = args.substr(0, args.length - 1);
    }

    // Path is /[area]/[controller]/[action]
    // Url output = /r/OtpLock/export?exportType=csv&search=foo
    $.get("/r/OtpLock/export" + args, null, function (data) {
        console.log(data);
    });
}

I wouldn't have expected a 404 here since it's really just hitting the controller action so I think maybe my routing isn't working? app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");

endpoints.MapAreaControllerRoute(
    name: "areas",
    areaName: "areas",
    pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
});

Have I made a mistake somewhere? Is it the routing? Thanks in advance!

8
  • Do you have a [Route(...)] attribute on the controller that contains the ExportData action? Commented Apr 20, 2021 at 13:02
  • I do... Currently it's decorated with [Area("r")] and [Route("r/[controller]/[action]")] Commented Apr 20, 2021 at 13:05
  • What is the controller name? Commented Apr 20, 2021 at 13:21
  • And isn't r in Route an extra? Try with /r/r/OtpLock/export and see if it works Commented Apr 20, 2021 at 13:22
  • 1
    Based on what you've described, it might work if you swap out [HttpGet("export")] for [ActionName("export")]. Commented Apr 20, 2021 at 13:27

1 Answer 1

1

With a route template of [Route("r/[controller]/[action]")] specified on the controller, the route for the ExportData action becomes:

r/OtpLock/ExportData

Adding [HttpGet("export")] to the ExportData method appends an existing segment, export, which changes its route to:

r/OtpLock/ExportData/export

This isn't the URL you're using for your AJAX calls, so the server responds with a 404.

To make this behave as you expect, there are a few options. e.g.:

  1. Use [ActionName("export")] instead of [HttpGet("export")]. This has the effect of providing export as the value for [action], rather than the default, which is the name of the method, ExportData. It also doesn't add anything extra to the route defined at the controller level.
  2. Remove the [HttpGet("export")] attribute and rename the ExportData action at the code level, by renaming the method to Export instead of ExportData.
  3. You might be able to remove both the [Route(...)] attribute from the controller and the [HttpGet(...)] attribute from the action. This would revert to using convention-based routing, which you've set up with MapAreaControllerRoute. This would also require either #1 or #2 above, but I'm not 100% on whether this will work for your setup.
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.