1
votes

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!

1
Do you have a [Route(...)] attribute on the controller that contains the ExportData action?Kirk Larkin
I do... Currently it's decorated with [Area("r")] and [Route("r/[controller]/[action]")]Ortund
What is the controller name?Alexander
And isn't r in Route an extra? Try with /r/r/OtpLock/export and see if it worksAlexander
Based on what you've described, it might work if you swap out [HttpGet("export")] for [ActionName("export")].Kirk Larkin

1 Answers

1
votes

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.