Reputation: 646
I created a quick project to prove a point and now well I guess I suck. For some reason I'm pulling 404 errors on an endpoint in this very simple site setup. I feel like I'm missing something minor but I can't seem to put my finger on it.
Any assistance would be great, I really just can't seem to wrap my head around how the routes are being created and / or how the route that I'm attempting to use is invalid?
I've only ever used the .NET framework, and .NET Core seems to be handling things slightly different.
Originally, I had just made it a form targeting the asp-controller / asp-action with method=POST. However that didn't work and I received a 404 page.
Then I tried using jQuery Ajax request, same result.
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseStatusCodePagesWithReExecute("/Home/Error/{0}");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
}
Home controller:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
var model = new ErrorViewModel {RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier};
if (Response.StatusCode.Equals(HttpStatusCode.NotFound))
return View("~/Views/Shared/404.cshtml", model);
return View(model);
}
[HttpPost]
public async Task<IActionResult> DownloadAsync([FromBody] DownloadModel model)
{
try
{
var youtube = new YoutubeClient();
var manifest = await youtube.Videos.Streams.GetManifestAsync(model.VideoId);
var info = manifest.GetMuxed().WithHighestVideoQuality();
if (info != null)
{
var file = $"{model.VideoId}.{info.Container}";
await youtube.Videos.Streams.DownloadAsync(info, file);
var bytes = await System.IO.File.ReadAllBytesAsync(file);
return File(bytes, "application/force-download", file);
}
}
catch (Exception e)
{
// TODO: Document Exception
this._logger.LogError(e, $"Download exception occurred.");
}
return BadRequest();
}
}
Index.cshtml
@model DownloadModel
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Yipper (Youtube Ripper)</h1>
<input type="text" asp-for="Url" class="url-input" id="url-textbox"/>
<button id="url-submit-btn" class="url-btn" type="submit">RIP</button>
</div>
@section Scripts
{
<script>
function download(e) {
e.preventDefault();
const request = {
"Url": $("#url-textbox").val()
}
console.log(request);
$.ajax('@Url.Action("DownloadAsync", "Home")',
{
method: "POST",
data: request
}).done(function(result) {
console.log(result);
}).fail(function(error) {
console.log(error);
});
}
$(function() {
$("#url-submit-btn").click(download);
});
</script>
}
Upvotes: 0
Views: 2178
Reputation: 18179
ASP.NET Core will trim the suffix Async from action names by default after .Net Core3.0,you can refer to the link.So you can change your ajax url to @Url.Action("Download", "Home")
,and then you post object to action,so you need to remove [FromBody]
.Here is a demo worked:
Controller:
[HttpPost]
public async Task<IActionResult> DownloadAsync(DownloadModel model)
{
return Ok();
}
Index.cshtml:
<div class="text-center">
<h1 class="display-4">Yipper (Youtube Ripper)</h1>
<input type="text" asp-for="Url" class="url-input" id="url-textbox" />
<button id="url-submit-btn" class="url-btn" type="submit">RIP</button>
</div>
@section Scripts
{
<script>
function download(e) {
e.preventDefault();
const request = {
"Url": $("#url-textbox").val()
}
console.log(request);
$.ajax('@Url.Action("Download", "Home")',
{
method: "POST",
data: request
}).done(function(result) {
console.log(result);
}).fail(function(error) {
console.log(error);
});
}
$(function() {
$("#url-submit-btn").click(download);
});
</script>
}
Upvotes: 3