Localization in ASP.NET CORE application - c#

I been trying for days to resolve localization in my ASP.NET Core 3.1 Car Sales project....it copmprises only one controller and three resource files. Default language is Serbian, the other two, german and english. Resx files are located in Resources folder within the project(Resource.resx,Resource.en-Us.resx,Resource.de-DE.resx. After debugging project, there's no visible mistake were displayenter image description hereed.
AutomobilController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using CarSales.Models;
using System.IO;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Localization;
using Microsoft.AspNetCore.Localization;
namespace CarSales.Controllers
{
public class AutomobilController : Controller
{
public IStringLocalizer<Resource> localizer;
private readonly AutomobilContext db;
public AutomobilController(AutomobilContext context, IStringLocalizer<Resource> localizer)
{
db = context;
this.localizer = localizer;
}
public IActionResult SetCulture(string culture,string sourceUrl)
{
Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName,CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)), new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) } );
return Redirect(sourceUrl);
}
public FileContentResult CitajAutomobil(int? Id)
{
if (Id == null)
{
return null;
}
Automobil auto = db.Automobili.Find(Id);
if (Id == null)
{
return null;
}
return File(auto.Fotografija, auto.TipFajla);
}
// GET: Automobil
public async Task<IActionResult> Index()
{
ViewBag.teststring = localizer["Detalji"];
return View(await db.Automobili.ToListAsync());
}
// GET: Automobil/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var automobil = await db.Automobili
.FirstOrDefaultAsync(m => m.Id == id);
if (automobil == null)
{
return NotFound();
}
return View(automobil);
}
// GET: Automobil/Create
public IActionResult Create()
{
return View();
}
public IActionResult ONama()
{
return View();
}
public IActionResult Kontakt()
{
return View();
}
// POST: Automobil/Create
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Fotografija,TipFajla,Marka,Model,Godiste,ZapreminaMotora,Snaga,Gorivo,Karoserija,Opis,Cena,Kontakt")] Automobil automobil, IFormFile OdabraniAutomobil)
{
if (OdabraniAutomobil == null)
{
ModelState.AddModelError("Fotografija", "Niste odabrali sliku");
}
if (ModelState.IsValid)
{
try
{
using (MemoryStream ms = new MemoryStream())
{
await OdabraniAutomobil.CopyToAsync(ms);
automobil.Fotografija = ms.ToArray();
}
automobil.TipFajla = OdabraniAutomobil.ContentType;
db.Add(automobil);
await db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
catch (Exception)
{
ViewBag.Greska = "Greska pri cuvanju slike Automobila";
}
}
return View(automobil);
}
// GET: Automobil/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var automobil = await db.Automobili.FindAsync(id);
if (automobil == null)
{
return NotFound();
}
return View(automobil);
}
// POST: Automobil/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Fotografija,TipFajla,Marka,Model,Godiste,ZapreminaMotora,Snaga,Gorivo,Karoserija,Opis,Cena,Kontakt")] Automobil automobil)
{
if (id != automobil.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
db.Update(automobil);
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!AutomobilExists(automobil.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(automobil);
}
// GET: Automobil/Delete/5
[Authorize]
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var automobil = await db.Automobili
.FirstOrDefaultAsync(m => m.Id == id);
if (automobil == null)
{
return NotFound();
}
return View(automobil);
}
// POST: Automobil/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var automobil = await db.Automobili.FindAsync(id);
db.Automobili.Remove(automobil);
await db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool AutomobilExists(int id)
{
return db.Automobili.Any(e => e.Id == id);
}
}
}
Startup.cs
using CarSales.Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using CarSales.Models;
using System.Globalization;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
namespace CarSales
{
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.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<AutomobilContext>(opcije => opcije.UseSqlServer(Configuration.GetConnectionString("DatabaseConnection")));
services.AddLocalization(opts => opts.ResourcesPath = "Resources");
services.AddMvc().AddDataAnnotationsLocalization(opts => { opts.DataAnnotationLocalizerProvider = (type, factory) => factory.Create(typeof(Resource)); }).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews();
services.AddRazorPages();
services.Configure<RequestLocalizationOptions>(
opts =>
{
var supported = new\[\]
{
new CultureInfo("en"),
new CultureInfo("sr"),
new CultureInfo("de-DE")
};
opts.DefaultRequestCulture = new RequestCulture(culture: "sr", uiCulture: "sr");
opts.SupportedCultures = supported;
opts.SupportedUICultures = supported;
}
);
}
// 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();
app.UseDatabaseErrorPage();
}
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.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseRequestLocalization();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Automobil}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
}
}][2]
Any help would be much appreciated...

Related

Action filter that sets language globally in ASP.NET Core using C#

I'm trying to create an ActionFilter that will read the Accept-Language header and find if it matches any value in locale and if it does not match, use the a default value which is "en".
First of all, this is my handler:
using MediatR;
using Microsoft.EntityFrameworkCore;
using Subscription.Domain.Common;
using Subscription.Domain.Exceptions;
using Subscription.Infrastructure.Configuration;
using System.Net;
namespace Subscription.API.Application.Package.Queries.Get
{
public class GetHandler : IRequestHandler<GetRequest, EntityResponseModel>
{
private readonly SubscriptionContext _context;
private readonly IHttpContextAccessor _httpContext;
public GetHandler(SubscriptionContext context, IHttpContextAccessor httpContext)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
_httpContext = httpContext;
}
public async Task<EntityResponseModel> Handle(GetRequest request, CancellationToken cancellationToken)
{
var lang = _httpContext.HttpContext.Request.Headers["Accept-Language"].ToString();
var packages = await _context.Packages.Where(x => !x.IsDeleted)
.Select(x => new GetResponseModel()
{
Id = x.Id,
BrandId = x.BrandId,
StartAt = x.StartAt,
IconUrl = x.IconUrl,
ImageUrl = x.ImageUrl,
CreatedAt = x.CreatedDate,
Title = x.PackageTranslations.FirstOrDefault(pt => pt.PackageId == x.Id && pt.Locale.Equals(lang)).Title,
Description = x.PackageTranslations.FirstOrDefault(pt => pt.PackageId == x.Id && pt.Locale.Equals(lang)).Description
}).ToListAsync();
if (!packages.Any())
{
throw new DomainException(HttpStatusCode.NotFound, "No record found.");
}
return new EntityResponseModel()
{
Data = packages
};
}
}
}
And this is the controller:
using Microsoft.AspNetCore.Mvc;
using MediatR;
using Subscription.API.Application.Package.Queries.Get;
using Subscription.API.Application.Bundle.Queries.GetById;
using Subscription.API.Filters;
namespace Subscription.API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class PackagesController : ControllerBase
{
private readonly IMediator _mediator;
public PackagesController(IMediator mediator)
{
_mediator = mediator;
}
[HttpGet]
[ValidateHeaders]
public async Task<ActionResult> GetAll()
{
var response = await _mediator.Send(new GetRequest() { });
return Ok(response);
}
}
}
This the filter class:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace Subscription.API.Filters
{
public class ValidateHeaders : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var headers = context.HttpContext.Request.Headers;
// need to do something here
}
}
}
So, basically what I need is to create a filter that:
Check the Accept-Language header if it have a value that matches locale
If it does not have a value that matches it, return string with the default value which is "en"
Any idea what I should do?
You can do this in 2 different ways;
Action Filter
Middleware
1.Action Filter
If you use this action filter, you have to write this attribute on each endpoint.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace Subscription.API.Filters
{
public class ValidateHeaders : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var languageHeader = context.HttpContext.Request.Headers.AcceptLanguage;
if (string.IsNullOrWhiteSpace(languageHeader))
context.HttpContext.Request.Headers.AcceptLanguage = "en";
}
}
}
2.Middleware
If you write it as middleware, it will be enough to place this middleware in the first place in the request pipeline.
public class ValidateHeadersMiddleware
{
private readonly RequestDelegate _next;
public ValidateHeadersMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var languageHeader = context.Request.Headers.AcceptLanguage;
if (string.IsNullOrWhiteSpace(languageHeader))
context.Request.Headers.AcceptLanguage = "en";
//Continue processing
if (_next != null)
await _next.Invoke(context);
}
}
This will effect all requests.
public static class MiddlewareExtension
{
public static IApplicationBuilder UseHeaderValidation(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ValidateHeadersMiddleware>();
}
}
In the Configure method in Startup.cs or minimal api configuration in Program.cs, use this middleware;
...
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHeaderValidation();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
...

'Page not found' error on my controller for my NET Core Web API

I am coding in C# on Visual Studio 2019, I am working on a 2019 MacBook. My app is a NET Core Web API 2.2. My controller is a API Controller with actions using Entity Framework.
I ran my app before I started the project and it worked fine, I have connected to my sql server, made my migrations and updated my database. When I run the app without debugging it works fine for the values controller (https://localhost:5001/api/values), but when I type in the name of my 'Loan controller' (https://localhost:5001/api/loan) it gets the HTTP error 'This localhost page can’t be found No web page was found for the web address: https://localhost:5001/api/loan'
Here is the code for the LoanController.cs file
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using WebAPI.Models;
namespace WebAPI.Controllers
{
public class LoanController : Controller
{
private readonly LoanContext _context;
public LoanController(LoanContext context)
{
_context = context;
}
// GET: Loan
public async Task<IActionResult> Index()
{
return View(await _context.Loans.ToListAsync());
}
// GET: Loan/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var loan = await _context.Loans
.FirstOrDefaultAsync(m => m.LoanCode == id);
if (loan == null)
{
return NotFound();
}
return View(loan);
}
// GET: Loan/Create
public IActionResult Create()
{
return View();
}
// POST: Loan/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("LoanCode,LoanID,BorrowerName,FundingAmount,RepaymentAmount")] Loan loan)
{
if (ModelState.IsValid)
{
_context.Add(loan);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(loan);
}
// GET: Loan/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var loan = await _context.Loans.FindAsync(id);
if (loan == null)
{
return NotFound();
}
return View(loan);
}
// POST: Loan/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("LoanCode,LoanID,BorrowerName,FundingAmount,RepaymentAmount")] Loan loan)
{
if (id != loan.LoanCode)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(loan);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!LoanExists(loan.LoanCode))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(loan);
}
// GET: Loan/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var loan = await _context.Loans
.FirstOrDefaultAsync(m => m.LoanCode == id);
if (loan == null)
{
return NotFound();
}
return View(loan);
}
// POST: Loan/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var loan = await _context.Loans.FindAsync(id);
_context.Loans.Remove(loan);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool LoanExists(int id)
{
return _context.Loans.Any(e => e.LoanCode == id);
}
}
}
Here is the ValuesController.cs file
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace WebAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return "value";
}
// POST api/values
[HttpPost]
public void Post([FromBody] string value)
{
}
// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody] string value)
{
}
// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}
Startup.cs file
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using WebAPI.Models;
namespace WebAPI
{
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.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<LoanContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DevConnection")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// 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.UseHttpsRedirection();
app.UseMvc();
}
}
}
Launchsetting.JSON file
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:41196",
"sslPort": 44395
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "api/values",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"WebAPI": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "api/values",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}
You need to add
[Route("api/[controller]")]
above
public class LoanController : Controller
So that it can locate the Loan route. This is already in place for your ValuesController.
See Microsoft docs - Token replacement in route templates
[controller] is replaced by the name of your controller ('Loan') as the routing is set up and so this then matches the route 'api/loan'.

Why Visual Studio automatically creates ApiController with all async methods? How to create ApiController with sync methods in it?

I have created a asp.net core webapi controller named StudentsController.cs using the functionality provided by Visual Studio which is API Controller with actions,using Entity Framework. It implements all the controller methods with return type async Task<ActionResult<>> which is asynchronous method implementation and it is auto generated by Visual Studio
Question is Why it creates all the methods async by its own and how can I create all the methods synchronously using the same auto generate feature of Visual Studio?
async example of controller
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Students.Models;
namespace Students.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class StudentsController : ControllerBase
{
private readonly StudentContext _context;
public StudentsController(StudentContext context)
{
_context = context;
}
// GET: api/Students
[HttpGet]
public async Task<ActionResult<IEnumerable<Student>>> GetStudents()
{
return await _context.Students.Include(d => d.Department).ToListAsync();
}
// GET: api/Students/5
[HttpGet("{id}")]
public async Task<ActionResult<Student>> GetStudent(int id)
{
var student = await _context.Students.Include(d => d.Department).FirstOrDefaultAsync(i => i.SId == id);
if (student == null)
{
return NotFound();
}
return student;
}
// PUT: api/Students/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://aka.ms/RazorPagesCRUD.
[HttpPut("{id}")]
public async Task<IActionResult> PutStudent(int id, Student student)
{
if (id != student.SId)
{
return BadRequest();
}
_context.Departments.Update(student.Department);
await _context.SaveChangesAsync();
_context.Entry(student).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!StudentExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return Ok();
}
//[HttpPut]
//public async Task<IActionResult> PutStudent(Student student)
//{
// _context.Departments.Update(student.Department);
// await _context.SaveChangesAsync();
// _context.Entry(student).State = EntityState.Modified;
// try
// {
// await _context.SaveChangesAsync();
// }
// catch (DbUpdateConcurrencyException)
// {
// if (!StudentExists(student.SId))
// {
// return NotFound();
// }
// else
// {
// throw;
// }
// }
// return Ok();
//}
// POST: api/Students
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://aka.ms/RazorPagesCRUD.
[HttpPost]
public async Task<ActionResult<Student>> PostStudent(Student student)
{
_context.Students.Add(student);
await _context.SaveChangesAsync();
return CreatedAtAction("GetStudent", new { id = student.SId }, student);
}
[HttpPost]
[Route("StudentList")]
public async Task<ActionResult<Student>> PostStudentList([FromBody] List<Student> student)
{
try
{
foreach (Student s in student)
{
_context.Students.Add(s);
}
_context.SaveChanges();
return CreatedAtAction("GetStudents", student, _context.Students.Include(d => d.Department));
}
catch(Exception ex)
{
return BadRequest();
}
}
// DELETE: api/Students/5
[HttpDelete("{id}")]
public async Task<ActionResult<Student>> DeleteStudent(int id)
{
var student = await _context.Students.FindAsync(id);
if (student == null)
{
return NotFound();
}
_context.Students.Remove(student);
await _context.SaveChangesAsync();
return student;
}
private bool StudentExists(int id)
{
return _context.Students.Any(e => e.SId == id);
}
}
}
sync example of controller
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using CourseCRUD.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace CourseCRUD.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class SubjectController : Controller
{
private readonly CourseContext _context;
public SubjectController(CourseContext context)
{
_context = context;
}
[HttpGet]
// GET:api/subject
public IActionResult GetSubjects()
{
try
{
var subjects = _context.subjects.ToList();
return Ok(subjects);
}
catch
{
return BadRequest();
}
}
[HttpPost]
public IActionResult AddSubject([FromBody]Subject subject)
{
try
{
_context.subjects.Add(subject);
_context.SaveChanges();
return CreatedAtAction("GetSubjets", subject);
}
catch
{
return BadRequest();
}
}
[HttpGet("{id}")]
public IActionResult GetSuject(int id)
{
try
{
var subject = _context.subjects.Find(id);
return Ok(subject);
}
catch
{
return BadRequest();
}
}
[HttpPut("id")]
[HttpPut("{id}")]
public IActionResult UpdateSubject(int id, Subject subject)
{
if (id != subject.SubjectId)
{
return BadRequest();
}
_context.Entry(subject).State = EntityState.Modified;
try
{
_context.SaveChanges();
return Ok(subject);
}
catch (DbUpdateConcurrencyException)
{
if (!SubjectDetailExist(id))
{
return NotFound();
}
else
{
throw;
}
}
}
private bool SubjectDetailExist(int id)
{
throw new NotImplementedException();
}
[HttpDelete("{id}")]
public IActionResult DeleteSubject(int id)
{
var result = _context.subjects.Find(id);
if (result == null)
{
return NotFound();
}
_context.subjects.Remove(result);
try
{
_context.SaveChanges();
return Ok(result);
}
catch
{
return BadRequest();
}
}
}
}```
it's a long time since I did anything with t4 templates so a bit rusty but you should perhaps start here
https://learn.microsoft.com/en-us/visualstudio/modeling/code-generation-and-t4-text-templates?view=vs-2019
You specify templates in text files and use rules to generate the required code.
<## output extension=".cs" #>
<## assembly name="System.Xml" #>
<#
System.Xml.XmlDocument configurationData = ...; // Read a data file here.
#>
namespace Fabrikam.<#= configurationData.SelectSingleNode("jobName").Value #>
{
... // More code here.
}
Depending on the values in the XML file, the generated .cs file would resemble the following:
namespace Fabrikam.FirstJob
{
... // More code here.
}
I don't know if controller scaffolding uses t4 templates but it wouldn't suprise me.. or something similar.
The async actions are generated by templates of scaffolding which locates in path similar to C:\ProgramFiles\dotnet\sdk\NuGetFallbackFolder\microsoft.visualstudio.web.codegenerators.mvc\2.0.3\Templates
You could change the template manually.Refer to
https://stackoverflow.com/a/39503291/10158551

MVC Controller unable to find Api Controller (same project)

(Sorry if my english sucks a little)
I'm trying to call an api method from a mvc controller but the mvc seems unable to find the method. I set the route in the mvc controller as
[Route("[controller]")]
and in the api controller as
[Route("api/[controller]")]
In the startup.cs file i added this command to enable default route
app.UseMvcWithDefaultRoute();
Mvc controller code:
[HttpGet]
public async Task<ActionResult> GetAll()
{
IEnumerable<Utente> utenti = null;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:57279/");
var Res = await client.GetAsync("api/utente/GetAll");
if (Res.IsSuccessStatusCode)
{
var readTask = Res.Content.ReadAsAsync<IList<Utente>>();
utenti = readTask.Result;
}
else
{
utenti = Enumerable.Empty<Utente>();
ModelState.AddModelError(string.Empty, "Server error. Please contact administrator.");
}
}
return View(utenti);
}
Api code:
[HttpGet]
public IHttpActionResult GetAll()
{
IList<Utente> utenti = null;
using (_utenteContext)
{
utenti = _utenteContext.Utenti.Select(u => new Utente()
{
id = u.id,
user = u.user,
password = u.password
}).ToList<Utente>();
}
if (utenti.Count == 0)
{
return NotFound();
}
return Ok(utenti);
}
The problem might be that I'm following an old example for both mvc and api controllers in same project, but I'd like if you guys could help me with it.
In the:
var Res = await client.GetAsync("api/utente/GetAll");
I always get {StatusCode: 404, ReasonPhrase: 'Not Found',...} no matter the changes I make to the code.
EDIT:
Whole Api Controller (I was trying also with a POST method but it doesn't work either)
using AdrianWebApi.Models;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace AdrianWebApi.Controllers.api
{
[Route("api/[controller]")]
public class UtenteController : ApiController
{
private readonly UtenteContext _utenteContext;
public UtenteController(UtenteContext context)
{
_utenteContext = context;
}
[HttpGet]
public IHttpActionResult GetAll()
{
IList<Utente> utenti = null;
using (_utenteContext)
{
utenti = _utenteContext.Utenti.Select(u => new Utente()
{
id = u.id,
user = u.user,
password = u.password
}).ToList<Utente>();
}
if (utenti.Count == 0)
{
return NotFound();
}
return Ok(utenti);
}
[HttpPost]
public IHttpActionResult PostNewUtente(Utente utente)
{
if (!ModelState.IsValid)
return BadRequest("Not a valid model");
using (_utenteContext)
{
_utenteContext.Utenti.Add(new Utente()
{
id = utente.id,
user = utente.user,
password = utente.password
});
_utenteContext.SaveChanges();
}
return Ok();
}
}
}
EDIT 2
Startup class if it's useful:
using AdrianWebApi.Models;
using AdrianWebApi.Models.DataManager;
using AdrianWebApi.Models.Repository;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace AdrianWebApi
{
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.AddDbContext<UtenteContext>(options =>{options.UseMySQL("server=localhost;database=dbutenti;User ID=root;password=root;");});
services.AddScoped<IDataRepository<Utente>, DataManager>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvcWithDefaultRoute();
}
}
}
EDIT 3 Post method MVC if someone is interested, working, at least for me:
[Route("Add")]
[System.Web.Http.HttpPost]
public ActionResult Add([FromForm]Utente utente)
{
if (utente.password == null)
{
return View();
}
else
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:57279/api/");
//HTTP POST
var postTask = client.PostAsJsonAsync<Utente>("utente", utente);
postTask.Wait();
var result = postTask.Result;
if (result.IsSuccessStatusCode)
{
return RedirectToAction("GetAll");
}
}
ModelState.AddModelError(string.Empty, "Server Error. Please contact administrator.");
return View(utente);
}
}
Try commenting out your controller and replacing it with this code below, then go to api/utente/ and see if you get a result. If you do then replace what you need with your code.
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
namespace AdrianWebApi.Controllers.api
{
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "Test 1", " Test 2" };
}
}
}

How do I resolve this ASP.NET MVC 5 HTTP Error that occurs for a specific page?

I understand that this general question has been asked and answered on here many times. Initially, this problem occurred for all of my web pages. I probably tried 15 different suggested fixes on here. Eventually using a response to a similar question, I ticked the 'Override application root URL' and now my homepage and the about page load correctly. However, the problem persists for my 'Movies' and 'Ratings' pages which are almost the same, which means it's most likely the code. I am obviously missing something and I'm very new to using c#, so I would greatly any help!
This is the error:
Server Error in '/' Application. The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its
dependencies) could have been removed, had its name changed, or is
temporarily unavailable. Please review the following URL and make
sure that it is spelled correctly.
Requested URL: /Movies
Here is my Movies controller:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Description;
using AllMovies.DAL;
using AllMovies.Models;
namespace AllMovies.Controllers
{
public class MoviesController : ApiController
{
private AllMoviesContext db = new AllMoviesContext();
// GET: api/Movies
public IQueryable<MovieDTO> GetMovies()
{
var movies = from m in db.Movies
select new MovieDTO()
{
Id = m.Id,
Name = m.Name,
Genre = m.Genre,
Budget = m.Budget,
Overview = m.Overview,
release_date = m.release_date,
Ratings = m.Ratings.Select(r => new RatingDTO()
{
Id = r.Id,
userId = r.userId,
rating_score = r.rating_score
}
).ToList()
};
return movies;
}
// GET: api/Movies/5
[ResponseType(typeof(MovieDTO))]
public async Task<IHttpActionResult> GetMovies(int id)
{
Movie m = await db.Movies.FindAsync(id);
if (m == null)
{
return NotFound();
}
MovieDTO movie = new MovieDTO
{
Id = m.Id,
Name = m.Name,
Genre = m.Genre,
Budget = m.Budget,
Overview = m.Overview,
release_date = m.release_date,
Ratings = m.Ratings.Select(r => new RatingDTO()
{
Id = r.Id,
userId = r.userId,
rating_score = r.rating_score
}
).ToList()
};
return Ok(movie);
}
// PUT: api/Movies/5
[ResponseType(typeof(void))]
public async Task<IHttpActionResult> PutMovies(int id, Movie movie)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != movie.Id)
{
return BadRequest();
}
db.Entry(movie).State = EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/Movies
[ResponseType(typeof(Movie))]
public async Task<IHttpActionResult> PostMovies(Movie movie)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Movies.Add(movie);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new { id = movie.Id }, movie);
}
// DELETE: api/Movies/5
[ResponseType(typeof(Movie))]
public async Task<IHttpActionResult> DeleteMovie(int id)
{
Movie movie = await db.Movies.FindAsync(id);
if (movie == null)
{
return NotFound();
}
db.Movies.Remove(movie);
await db.SaveChangesAsync();
return Ok(movie);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool MovieExists(int id)
{
return db.Movies.Count(e => e.Id == id) > 0;
}
}
}

Categories

Resources