How to get custom attribute name for action in asp.net core? - asp.net

I have created an attribute for action names. I want to get the attribute names in my service. I tried so many solutions but it doesn't return anything.
This is my attribute class:
public class CustomeAttribute : ActionFilterAttribute
{
public string Name { get; set; }
}
This is the action that I used the attribute for:
[Custome(Name ="ُShow courses")]
public IActionResult Index()
{
var course = _courseService.GetAllCourses();
return View(course);
}
This is the method that I want to return the attribute name:
public IList<ActionAndControllerName> AreaAndActionAndControllerNamesList(Assembly asm)
{
var contradistinction = asm.GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type))
.SelectMany(type =>
type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly |
BindingFlags.Public))
.Select(x => new
{
Controller = x.DeclaringType?.Name,
//Action = x.Name,
//Action=x.DeclaringType?.GetCustomAttributes(typeof(CustomeAttribute), false),
//
Action=x.DeclaringType?.CustomAttributes.Where(c=>c.AttributeType==typeof(CustomeAttribute)),
// Action=x.DeclaringType?.GetCustomAttributes(typeof(CustomeAttribute), false),
// Action=x.DeclaringType?.CustomAttributes(typeof(CustomeAttribute), false),
//Action=x.DeclaringType?.GetCustomAttribute(typeof(CustomeAttribute), false),
Action=x.DeclaringType?.GetCustomAttributes<CustomeAttribute>(),
//Action = x.DeclaringType?.GetCustomAttributes().Where(a => a.GetType() ==
typeof(CustomeAttribute))
Area = x.DeclaringType?.CustomAttributes.Where(c => c.AttributeType ==
typeof(AreaAttribute)),
});
}
As I said I tried the solutions above that are commented but none of them worked. What should I do?

You can try to save Name to some place in ActionfilterAttribute.Here is a demo to save data to session in OnActionExecuting method:
TestController:
SomeOtherClass _someOtherClass;
public TestController(SomeOtherClass someOtherClass)
{
_someOtherClass = someOtherClass;
}
[Custome(Name = "Show courses")]
public IActionResult TestActionFilterAttribute()
{
var Name = _someOtherClass.TestGet();
return Ok();
}
SomeOtherClass:
public class SomeOtherClass
{
private readonly IHttpContextAccessor _httpContextAccessor;
private ISession _session => _httpContextAccessor.HttpContext.Session;
public SomeOtherClass(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public string TestGet()
{
return _session.GetString("Custome_Name");
}
}
Startup.cs(IHttpContextAccessor can help get seesion outside controller):
public void ConfigureServices(IServiceCollection services)
{
...
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromDays(1);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<SomeOtherClass, SomeOtherClass>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
...
}
CustomeAttribute:
public class CustomeAttribute: ActionFilterAttribute
{
public string Name { get; set; }
public override void OnActionExecuting(ActionExecutingContext
context)
{
if (Name != null)
{
context.HttpContext.Session.SetString("Custome_Name", Name);
}
}
public override void OnActionExecuted(ActionExecutedContext
context)
{
}
}
result:

I found the solution.I shouldn't have used "DeclaringType" in service.
This is the solution:
var contradistinction = asm.GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type))
.SelectMany(type =>
type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly |
BindingFlags.Public))
.Select(x => new
{
Controller = x.DeclaringType?.Name,
Action = x.GetCustomAttribute<CustomeAttribute>()?.Name,
Area = x.DeclaringType?.CustomAttributes.Where(c => c.AttributeType ==
typeof(AreaAttribute)),
});

Related

DbContext in Service triggered by Hangfire

I have a .NET 6 Razor Pages app that triggers background tasks and then informs the user of their status via SignalR.
I'm trying to use Database1 context in the PerformBackgroundJob method, but it's disposed. What technique should I use to inject Database1 context in PerformBackgroundJob, or how else can I get this to work?
namespace Toolkat.Pages
{
public class ProcessModel : PageModel
{
private readonly Database1Context _context;
private readonly ToolkatContext _tkcontext;
private IConfiguration configuration;
private readonly IQueue _queue;
private readonly IHubContext<JobHub> _hubContext;
static ServerConnection conn;
static Server server;
static Job job;
public ProcessModel(
Database1Context context,
ToolkatContext tkcontext,
IConfiguration _configuration,
IQueue queue,
IHubContext<JobHub> hubContext)
{
_context = context;
_tkcontext = tkcontext;
configuration = _configuration;
_queue = queue;
_hubContext = hubContext;
}
public IList<CustomFileImport> CustomFileImport { get; set; } = default!;
[BindProperty]
public CustomFileImport CustomFileImportNumberTwo { get; set; } = default!;
public async Task OnGetAsync()
{
if (_context.CustomFileImports != null)
{
CustomFileImport = await _context.CustomFileImports
.Include(c => c.FileImportType)
.Include(c => c.FileImportStatus)
.Where(i => i.FileImportStatusId.Equals(1))
.ToListAsync();
}
}
public async Task<IActionResult> OnPostAsync(int[] fileImportId)
{
//Generate GUID
Guid jobId = Guid.NewGuid();
//Update FileImportItems with GUID
foreach (var id in fileImportId)
{
if (/*id == null ||*/ _context.CustomFileImports == null)
{
return NotFound();
}
var customfileimport = await _context.CustomFileImports.FirstOrDefaultAsync(m => m.FileImportId == id);
if (customfileimport == null)
{
return NotFound();
}
customfileimport.ProcessId = jobId;
await _context.SaveChangesAsync();
}
_queue.QueueAsyncTask(() => PerformBackgroundJob(jobId));
return RedirectToPage("./Result", new { jobId });
}
private async Task PerformBackgroundJob(Guid jobId /*CancellationToken cancellationToken*/)
{
await _hubContext.Clients.Group(jobId.ToString()).SendAsync("progress", "PerformBackgroundJob Started");
/*
var customFileImports = await _context.CustomFileImports
.Include(c => c.FileImportType)
.Where(i => i.ProcessId.Equals(jobId))
.ToListAsync();
*/
Debug.WriteLine("ProviderName:" + _context.Database.ProviderName);
/*
foreach (var f in customFileImports)
{
await _hubContext.Clients.Group(jobId.ToString()).SendAsync("progress", WebUtility.HtmlEncode(f.FileName));
}
*/
}
}
}
I had to combine lessons from lots of articles to figure this out. Hangfire has a nice way of approaching this.
Replace
_queue.QueueAsyncTask(() => PerformBackgroundJob(jobId));
With
BackgroundJob.Enqueue<ProcessFilesService>(x => x.DoWork());
Passing dependencies
and create this class
public class ProcessFilesService
{
IServiceProvider _serviceProvider;
public ProcessFilesService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void DoWork()
{
using var scope = _serviceProvider.CreateScope();
var ctx = scope.ServiceProvider.GetRequiredService<MyDatabaseContext>();
using var hubScope = _serviceProvider.CreateScope();
var _hubContext = hubScope.ServiceProvider.GetRequiredService<JobHub>();
Debug.WriteLine(ctx.Database.ProviderName);
}
}
Hmm...I didn't need to register it as a service in program.cs and it appears to still be working. Will have to learn more about that.

Identity UserManager not able to connect to DB

I am trying to implement IdentityFramework in my .NET Core 6 Web API Application.
Following is my settings.
public class ApplicationUser : IdentityUser<int>
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
My connection string is :
"ConnectionStrings": {
"connectionString": "Server=DESKTOP-HO7FAAD\\SQLEXPRESS; Database=AviaryDB; Trusted_Connection=True; MultipleActiveResultSets=true;"
}
Program.cs
builder.Services.AddIdentity<ApplicationUser, IdentityRole<int>>()
.AddEntityFrameworkStores<ApplicationDBContext>()
.AddDefaultTokenProviders();
builder.Services.AddDbContext<ApplicationDBContext>(db => db.UseSqlServer(builder.Configuration.GetConnectionString("connectionString")));
ApplicationDBContext.cs
public class ApplicationDBContext : IdentityDbContext<ApplicationUser, IdentityRole<int>, int>
{
public ApplicationDBContext(DbContextOptions<ApplicationDBContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
builder.Entity<ApplicationUser>(entity =>
{
entity.Property(p => p.Id).ValueGeneratedOnAdd();
entity.Property(p => p.FirstName).HasMaxLength(150);
entity.Property(p => p.LastName).HasMaxLength(150);
entity.ToTable(name: "Users");
});
builder.Entity<IdentityRole<int>>(entity =>
{
entity.Property(p => p.Id).ValueGeneratedOnAdd();
entity.ToTable(name: "Roles");
});
builder.Entity<IdentityUserRole<int>>(entity =>
{
entity.ToTable("UserRoles");
//in case you chagned the TKey type
entity.HasKey(key => new { key.UserId, key.RoleId });
});
builder.Entity<IdentityUserClaim<int>>(entity =>
{
entity.ToTable("UserClaims");
});
builder.Entity<IdentityUserLogin<int>>(entity =>
{
entity.ToTable("UserLogins");
//in case you chagned the TKey type
entity.HasKey(key => new { key.ProviderKey, key.LoginProvider });
});
builder.Entity<IdentityRoleClaim<int>>(entity =>
{
entity.ToTable("RoleClaims");
});
builder.Entity<IdentityUserToken<int>>(entity =>
{
entity.ToTable("UserTokens");
//in case you chagned the TKey type
entity.HasKey(key => new { key.UserId, key.LoginProvider, key.Name });
});
}
}
AccountController.cs
public class AccountController : ControllerBase
{
private readonly UserManager<ApplicationUser> _userManager;
public AccountController(
UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
[AllowAnonymous]
[HttpPost]
[Route("register")]
public async Task<ActionResult> Register([FromBody] RegisterModel model)
{
try
{
var userExists = await _userManager.FindByNameAsync(model.Username);
if (userExists != null)
return StatusCode(StatusCodes.Status500InternalServerError, new Response { Status = "Error", Message = "User already exists!" });
ApplicationUser user = new()
{
Email = model.Email,
SecurityStamp = Guid.NewGuid().ToString(),
UserName = model.Username,
};
var result = await _userManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
return StatusCode(StatusCodes.Status500InternalServerError, new Response { Status = "Error", Message = "User creation failed! Please check user details and try again." });
return Ok("User created successfully!");
}
catch(Exception ex)
{
throw ex;
}
}
}
And I am getting the following error. Can anyone guide me what I am doing wrong?

Getting internal server error (500) in response after insert/update

CRUD operation works fine with the database but i am getting 500 internal server error for POST/PUT operation. I am getting 200 for GET/DELETE.
I worked with crud operation in ASP.NET and my code is running in prod. I have a requirement to migrate that to .NET Core. While testing i found that CRUD operations are working fine and i can see the changes related to data inside the SQL database but for Insert/Update, I am getting 500 error in response.
Code for .NET Framework (Working):-
public class ActivityUpdatesController : ApiController
{
private PortfolioMgmtEntities db = new PortfolioMgmtEntities();
// GET: api/ActivityUpdates
public IQueryable<ActivityUpdate> GetActivityUpdates()
{
return db.ActivityUpdates;
}
[Route("api/activityUpdates/getByProjectId")]
public IQueryable<ActivityUpdate> getActivityUpdatesByProjectId(int projectId)
{
IQueryable<ActivityUpdate> activityUpdates = from r in db.ActivityUpdates
where r.ProjectID == projectId
select r;
return activityUpdates;
}
// GET: api/ActivityUpdates/5
[ResponseType(typeof(ActivityUpdate))]
public IHttpActionResult GetActivityUpdate(int id)
{
ActivityUpdate activityUpdate = db.ActivityUpdates.Find(id);
if (activityUpdate == null)
{
return NotFound();
}
return Ok(activityUpdate);
}
// PUT: api/ActivityUpdates/5
[ResponseType(typeof(void))]
public IHttpActionResult PutActivityUpdate(int id, ActivityUpdate activityUpdate)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != activityUpdate.RecordID)
{
return BadRequest();
}
db.Entry(activityUpdate).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!ActivityUpdateExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/ActivityUpdates
[ResponseType(typeof(ActivityUpdate))]
[Route("api/activityUpdates/create")]
public IHttpActionResult PostActivityUpdate(int projectId, [FromBody] ActivityUpdate activityUpdate)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
activityUpdate.ProjectID = projectId;
activityUpdate.UpdatedDate = DateTime.Now;
db.ActivityUpdates.Add(activityUpdate);
db.SaveChanges();
IQueryable<ActivityUpdate> activityUpdates = from au in db.ActivityUpdates
where au.ProjectID == projectId
select au;
return CreatedAtRoute("DefaultApi", new { controller = "ActivityUpdates" }, activityUpdates);
}
// DELETE: api/ActivityUpdates/5
[ResponseType(typeof(ActivityUpdate))]
public IHttpActionResult DeleteActivityUpdate(int id)
{
ActivityUpdate activityUpdate = db.ActivityUpdates.Find(id);
if (activityUpdate == null)
{
return NotFound();
}
db.ActivityUpdates.Remove(activityUpdate);
db.SaveChanges();
return Ok(activityUpdate);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool ActivityUpdateExists(int id)
{
return db.ActivityUpdates.Count(e => e.RecordID == id) > 0;
}
}
WebAPiConfig.cs
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.EnableCors(new EnableCorsAttribute("*", "*", "GET,PUT,POST,DELETE"));
}
Code for .NET Core (Not Working):-
public class ActivityUpdatesController : Controller
{
private aeportfoliomgmtdbContext db = new aeportfoliomgmtdbContext();
// GET: api/ActivityUpdates
public IQueryable<ActivityUpdates> GetActivityUpdates()
{
return db.ActivityUpdates;
}
[HttpGet]
[Route("api/activityUpdates/getByProjectId")]
public IQueryable<ActivityUpdates> getActivityUpdatesByProjectId(int projectId)
{
IQueryable<ActivityUpdates> activityUpdates = from r in db.ActivityUpdates
where r.ProjectId == projectId
select r;
return activityUpdates;
}
[HttpPost]
[Route("api/activityUpdates/create")]
public IActionResult PostActivityUpdate(int projectId, [FromBody] ActivityUpdates activityUpdate)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
activityUpdate.ProjectId = projectId;
activityUpdate.UpdatedDate = DateTime.Now;
db.ActivityUpdates.Add(activityUpdate);
db.SaveChanges();
IQueryable<ActivityUpdates> activityUpdates = from au in db.ActivityUpdates
where au.ProjectId == projectId
select au;
return CreatedAtRoute("DefaultApi", new { controller = "ActivityUpdates" }, activityUpdates);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool ActivityUpdateExists(int id)
{
return db.ActivityUpdates.Count(e => e.RecordId == id) > 0;
}
}
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.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
}
// 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
{
app.UseExceptionHandler("/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.UseSpaStaticFiles();
app.UseCors("CorsPolicy");
app.UseMvc(routes =>
{
routes.MapRoute(
name: "DefaultApi",
template: "api/{controller}/{id}");
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
}
I am unable to find where is the mistake. Could you please help me to solve this issue? Any help will be appreciated.
If you want to return GetActivityUpdates like web api, try to define the route name above the GetActivityUpdates method.
[HttpGet("api/activityUpdates/GetActivityUpdates", Name = "GetActivityUpdates")]
public IQueryable<ActivityUpdates> GetActivityUpdates()
{
return db.ActivityUpdates;
}
[HttpGet]
[Route("api/activityUpdates/getByProjectId")]
public IQueryable<ActivityUpdates> getActivityUpdatesByProjectId(int projectId)
{
IQueryable<ActivityUpdates> activityUpdates = from r in db.ActivityUpdates
where r.ProjectId == projectId
select r;
return activityUpdates;
}
[HttpPost]
[Route("api/activityUpdates/create")]
public IActionResult PostActivityUpdate(int projectId, [FromBody] ActivityUpdates activityUpdate)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
activityUpdate.ProjectId = projectId;
activityUpdate.UpdatedDate = DateTime.Now;
db.ActivityUpdates.Add(activityUpdate);
db.SaveChanges();
IQueryable<ActivityUpdates> activityUpdates = from au in db.ActivityUpdates
where au.ProjectId == projectId
select au;
return CreatedAtRoute("GetActivityUpdates", activityUpdates);
}
Please try to return Ok() from your post method not created route and check is it working or not. If it is work then may be you does not define the route that you use in created route.

Add to cart function returns a null value

I have been following a tutorial on how to add shopping cart functionality for a website using .net core but when I click the "Add to cart" button, it gives me a null value in my action method.
Add to cart returns a null value
What should be the error here?
Here is my Controller Class
namespace SanMarinoClassicWebsite.Controllers
{
public class ShoppingCartController : Controller
{
private readonly IPieRepository _pieRepository;
private readonly ShoppingCart _shoppingCart;
public ShoppingCartController(IPieRepository pieRepository, ShoppingCart shoppingCart)
{
_pieRepository = pieRepository;
_shoppingCart = shoppingCart;
}
public ViewResult Index()
{
var items = _shoppingCart.GetShoppingCartItems();
_shoppingCart.ShoppingCartItems = items;
var shoppingCartViewModel = new ShoppingCartViewModel
{
ShoppingCart = _shoppingCart,
ShoppingCartTotal = _shoppingCart.GetShoppingCartTotal()
};
return View(shoppingCartViewModel);
}
public RedirectToActionResult AddToShoppingCart(int pieId)
{
var selectedPie = _pieRepository.Pies.FirstOrDefault(p => p.PieId == pieId);
if (selectedPie != null)
{
_shoppingCart.AddToCart(selectedPie, 1);
}
return RedirectToAction("Index");
}
public RedirectToActionResult RemoveFromShoppingCart(int pieId)
{
var selectedPie = _pieRepository.Pies.FirstOrDefault(p => p.PieId == pieId);
if (selectedPie != null)
{
_shoppingCart.RemoveFromCart(selectedPie);
}
return RedirectToAction("Index");
}
}
}
ShoppingCart Model
namespace SanMarinoClassicWebsite.Models
{
public class ShoppingCart
{
private readonly AppDbContext _appDbContext;
private ShoppingCart(AppDbContext appDbContext)
{
_appDbContext = appDbContext;
}
public string ShoppingCartId { get; set; }
public List<ShoppingCartItem> ShoppingCartItems { get; set; }
public static ShoppingCart GetCart(IServiceProvider services)
{
ISession session = services.GetRequiredService<IHttpContextAccessor>()?
.HttpContext.Session;
var context = services.GetService<AppDbContext>();
string cartId = session.GetString("CartId") ?? Guid.NewGuid().ToString();
session.SetString("CartId", cartId);
return new ShoppingCart(context) { ShoppingCartId = cartId };
}
public void AddToCart(Pie pie, int amount)
{
var shoppingCartItem =
_appDbContext.ShoppingCartItems.SingleOrDefault(
s => s.Pie.PieId == pie.PieId && s.ShoppingCartId == ShoppingCartId);
if (shoppingCartItem == null)
{
shoppingCartItem = new ShoppingCartItem
{
ShoppingCartId = ShoppingCartId,
Pie = pie,
Amount = 1
};
_appDbContext.ShoppingCartItems.Add(shoppingCartItem);
}
else
{
shoppingCartItem.Amount++;
}
_appDbContext.SaveChanges();
}
public int RemoveFromCart(Pie pie)
{
var shoppingCartItem =
_appDbContext.ShoppingCartItems.SingleOrDefault(
s => s.Pie.PieId == pie.PieId && s.ShoppingCartId == ShoppingCartId);
var localAmount = 0;
if (shoppingCartItem != null)
{
if (shoppingCartItem.Amount > 1)
{
shoppingCartItem.Amount--;
localAmount = shoppingCartItem.Amount;
}
else
{
_appDbContext.ShoppingCartItems.Remove(shoppingCartItem);
}
}
_appDbContext.SaveChanges();
return localAmount;
}
public List<ShoppingCartItem> GetShoppingCartItems()
{
return ShoppingCartItems ??
(ShoppingCartItems =
_appDbContext.ShoppingCartItems.Where(c => c.ShoppingCartId == ShoppingCartId)
.Include(s => s.Pie)
.ToList());
}
public void ClearCart()
{
var cartItems = _appDbContext
.ShoppingCartItems
.Where(cart => cart.ShoppingCartId == ShoppingCartId);
_appDbContext.ShoppingCartItems.RemoveRange(cartItems);
_appDbContext.SaveChanges();
}
public decimal GetShoppingCartTotal()
{
var total = _appDbContext.ShoppingCartItems.Where(c => c.ShoppingCartId == ShoppingCartId)
.Select(c => c.Pie.Price * c.Amount).Sum();
return total;
}
}
}
Startup.cs
public class Startup
{
private IConfigurationRoot _configurationRoot;
public Startup(IHostingEnvironment hostingEnvironment)
{
_configurationRoot = new ConfigurationBuilder()
.SetBasePath(hostingEnvironment.ContentRootPath)
.AddJsonFile("appsettings.json")
.Build();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(_configurationRoot.GetConnectionString("DefaultConnection")));
services.AddTransient<ICategoryRepository, CategoryRepository>();
services.AddTransient<IPieRepository, PieRepository>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<ShoppingCart>(sp => ShoppingCart.GetCart(sp));
services.AddMvc();
services.AddMemoryCache();
services.AddSession();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseStatusCodePages();
app.UseStaticFiles();
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "categoryfilter",
template:"Pie/{action}/{category?}",
defaults: new {Controller ="Pie", action ="List"});
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
I have found my error and it seems that I used asp-route tag helper incorrectly. I have used asp-route-id instead of asp-route-pieId,
here are the snippets
<a class="btn btn-primary" asp-controller="ShoppingCart" asp-action="AddToShoppingCart" asp-route-id="#Model.PieId">
<a class="btn btn-primary" asp-controller="ShoppingCart" asp-action="AddToShoppingCart" asp-route-pieId="#Model.PieId">

ASP.NET Core 2 Versioning and Culture in Route

friends! I'm trying to add in route of ASP.NET Core 2.0 Web API Versioning (Microsoft.Asp.NetCore.Mvc.Versioning package) and Localization (Microsoft.AspNetCore.Localization) to take url like:
"api/{culture=en-US}/v{version:apiVersion}/[controller]"
Separately, they work, but together constantly error 404..(
[ApiVersion("1")]
[Route("api/{culture=en-US}/v{version:apiVersion}/[controller]")]
public class ValuesController : Controller
{
private readonly IStringLocalizer<ValuesController> _localizer;
public ValuesController(IStringLocalizer<ValuesController> localizer)
{
_localizer = localizer;
}
[HttpGet]
public IActionResult Get()
{
var result = $"{_localizer["Title"].Value}";
return Ok(result);
}
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization(x => x.ResourcesPath = "Resources");
services.AddRouteAnalyzer();
services.AddApiVersioning(opt => {
opt.ReportApiVersions = true;
opt.AssumeDefaultVersionWhenUnspecified = true;
opt.DefaultApiVersion = new ApiVersion(1, 0);
});
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouter(routes =>
{
routes.MapMiddlewareRoute("api/{culture=en}/{*mvcRoute}", subApp =>
{
var supportedCultures = new[]
{
new CultureInfo("en"),
new CultureInfo("ru"),
};
var localizationOptions = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
};
var requestProvider = new RouteDataRequestCultureProvider();
localizationOptions.RequestCultureProviders.Insert(0, requestProvider);
subApp.UseRequestLocalization(localizationOptions);
subApp.UseMvcWithDefaultRoute();
});
});
}
}

Resources