Validation Context is always NULL - asp.net-core

I have implemented a custom validation attribute to check column uniqueness. I want to check if the provided value already exists in the database or not.
Here is my code:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class UniqueAttribute : ValidationAttribute
{
public UniqueAttribute()
{
}
public override bool RequiresValidationContext => true;
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
return ValidationResult.Success;
}
}
the validationContext in IsValid method always returns null. How it can be fixed?
Startup.cs : ConfigureServices method
public void ConfigureServices(IServiceCollection services)
{
services.AddApiVersioning(o =>
{
o.ReportApiVersions = true;
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1, 0);
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
services.AddScoped<IClaimsTransformation, ClaimsTransformation>();
RegisterRepository(services);
RegisterServices(services);
RegisterAutoMapper(services);
services.AddControllersWithViews()
.AddJsonOptions(opts => opts.JsonSerializerOptions.PropertyNamingPolicy = null);
services.AddRazorPages();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
// 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.UseMigrationsEndPoint();
}
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();
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseRouting();
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
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");
}
});
}
Model class :
public class Category
{
[Unique]
public string Name { get; set; }
public string Description { get; set; }
}

Below is an example to check if the provided value already exists in the database or not, you can refer to it.
UniqueAttribute:
public class UniqueAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value,ValidationContext validationContext)
{
var context = (MvcMovieContext)validationContext.GetService(typeof(MvcMovieContext));//change the MvcMovieContext to your DbContext
if (!context.Movie.Any(a => a.Company == value.ToString()))
{
return ValidationResult.Success;
}
return new ValidationResult("Company exists");
}
}
Movie:
public class Movie
{
[Unique]
public string Company { get; set; }
}
Create view:
#model MvcMovie.Models.Movie
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Company" class="control-label"></label>
<input asp-for="Company" class="form-control" />
<span asp-validation-for="Company" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
result:

Related

Change Default Page in Web API project .net core 6 MVC

I have ASP.net core **WebAPI ** project after that I create Scaffolded item witch Identity inside this project. How can I change Default page to Identity/page/login.cshtml instead of ~/swagger/index.html
Thanks
change default page from ~/swagger/index.html to Identity/page/login.cshtml
Thanks
my Code here
AppUser.cs
public class AppUser: IdentityUser <int>
{
public string FullName { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; }
}
program.cs
builder.Services.ConfigureApplicationCookie(options =>
{
options.LoginPath = $"/Identity/Account/Login";
options.LogoutPath = $"/Identity/Account/Logout";
options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
});
AppDbContext.cs
public class AppDbContext : IdentityDbContext<AppUser, IdentityRole<int>, int>
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
...........................................
}
_LoginPartial.cshtml
#using Claim.Data.Entities
#using Microsoft.AspNetCore.Identity
#inject SignInManager<AppUser> SignInManager
#inject UserManager<AppUser> UserManager
When I Test to click to Login to go to Login Page
error:
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.SignInManager`1[Microsoft.AspNetCore.Identity.IdentityUser]' while attempting to activate 'XXXXXXX.Areas.Identity.Pages.Account.LoginModel'.
hi have fixed the problem. I have to change the Login.cshtmal.sc file.
However I got problem Authentication, cannot login
SignInManager.IsSignedIn(User) <- return claims = 0
_loginPatial.cshtml
#using Microsoft.AspNetCore.Identity
#inject SignInManager<IdentityUser> SignInManager
#inject UserManager<IdentityUser> UserManager
<ul class="navbar-nav">
#if (SignInManager.IsSignedIn(User))
{
<li class="nav-item">
<a id="manage" class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello #UserManager.GetUserName(User)!</a>
</li>
<li class="nav-item">
<form id="logoutForm" class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="#Url.Action("Index", "Home", new { area = "" })">
<button id="logout" type="submit" class="nav-link btn btn-link text-dark">Logout</button>
</form>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link text-dark" id="register" asp-area="Identity" asp-page="/Account/Register">Register</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" id="login" asp-area="Identity" asp-page="/Account/Login">Login</a>
</li>
}
</ul>
Login.cshtml.cs
if (result.Succeeded) <------ true
public async Task<IActionResult> OnPostAsync(string? returnUrl = null)
{
returnUrl ??= Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
..............................
program.cs
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddRazorPages();
builder.Services.AddDbContext<AppDbContext>(opt =>
{
opt.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
});
builder.Services.AddIdentity<IdentityUser, IdentityRole>().AddDefaultTokenProviders()
.AddEntityFrameworkStores<AppDbContext>();
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Constants.SecretKey)),
ValidateAudience = true,
ValidIssuer = Constants.Issuer,
ValidAudience = Constants.Audience,
RequireExpirationTime = true,
};
});
builder.Services.AddScoped<IUserClaimService, UserClaimServices>();
builder.Services.AddSingleton<IEmailSender, EmailSender>();
builder.Services.ConfigureApplicationCookie(options =>
{
options.LoginPath = $"/Identity/Account/Login";
options.LogoutPath = $"/Identity/Account/Logout";
options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
});
//builder.Services.AddMvc().AddRazorPagesOptions(options =>
//{
// options.Conventions.AddAreaPageRoute("Identity", "/Account/Login", "");
//}
// );
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
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.UseAuthorization();
app.MapRazorPages();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();

ASP.NET Core localize .cs file in Razor Pages

There is a project on ASP.NET 5.0 with Identity.
Need help in how to translate messages in .cs files Razor Page.
Startup.cs looks like that
namespace localizeTest
{
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.AddLocalization(opt => { opt.ResourcesPath = "Resources"; });
services.AddMvc().AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix).AddDataAnnotationsLocalization();
services.Configure<RequestLocalizationOptions>(
opt =>
{
var suppoortedCulteres = new List<CultureInfo>
{
new CultureInfo("ru"),
new CultureInfo("en")
};
opt.DefaultRequestCulture = new RequestCulture("ru");
opt.SupportedCultures = suppoortedCulteres;
opt.SupportedUICultures = suppoortedCulteres;
}
);
services.AddDNTCaptcha(options =>
{
options.UseCookieStorageProvider();
});
string connection = Configuration["ConnectionStrings:DefaultConnection"];
ServerVersion vesrion = ServerVersion.AutoDetect(connection);
services.AddDbContext<ApplicationDbContext>(options =>
options.UseMySql(connection, vesrion));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews();
services.AddRazorPages();
}
// 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.UseMigrationsEndPoint();
}
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.UseAuthorization();
app.UseRequestLocalization(app.ApplicationServices.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value);
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
In the Resources folder created two files:
/Areas/Identity/Pages/Account/Login.en.resx
/Areas/Identity/Pages/Account/Login.ru.resx
Sample page
Areas/Identity/Pages/Account/Login.cshtml
#page
#model LoginModel
#inject Microsoft.AspNetCore.Mvc.Localization.IViewLocalizer localizer
#{
ViewData["Title"] = localizer["Login"];
}
<div class="container">
<div class="row h-100">
<div class="col-12 col-md-10 mx-auto my-auto">
<div class="card auth-card">
<div class="card-body">
<h1 class="mb-4">#ViewData["Title"]</h1>
<h4 class="pb-2">#localizer["Welcome"]</h4>
<form id="account" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Email">#localizer["Email"]</label>
<input asp-for="Input.Email" class="form-control" placeholder="#localizer["YourEmail"]" required="">
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Password">#localizer["Password"]</label>
<input asp-for="Input.Password" class="form-control" placeholder="#localizer["YourPassword"]" required="">
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input class="custom-control-input" asp-for="Input.RememberMe">
<label class="custom-control-label" asp-for="Input.RememberMe">#localizer["RememberMe"]</label>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">#localizer["SignIn"]</button>
</div>
<div class="form-group">
<p>
<a id="forgot-password" asp-page="./ForgotPassword">#localizer["ForgotPass"]</a>
</p>
<p>
<a asp-page="./Register" asp-route-returnUrl="#Model.ReturnUrl">#localizer["ЗарегестрироватьсяКакНовый"]</a>
</p>
<p>
<a id="resend-confirmation" asp-page="./ResendEmailConfirmation">#localizer["EmailConf"]</a>
</p>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
#section Scripts {
<partial name="_ValidationScriptsPartial" />
}
Good, localize in Page View work it!
But, localize in Page Model not work.
File Areas/Identity/Pages/Account/Login.cshtml.cs
namespace localizeTest.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class LoginModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly ILogger<LoginModel> _logger;
private readonly IStringLocalizer<LoginModel> _stringLocalizer;
public LoginModel(SignInManager<IdentityUser> signInManager,
ILogger<LoginModel> logger,
UserManager<IdentityUser> userManager,
IStringLocalizer<LoginModel> stringLocalizer)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
_stringLocalizer = stringLocalizer;
}
[BindProperty]
public InputModel Input { get; set; }
public IList<AuthenticationScheme> ExternalLogins { get; set; }
public string ReturnUrl { get; set; }
[TempData]
public string ErrorMessage { get; set; }
public class InputModel
{
[Display(Name = "Email")]
[Required(ErrorMessage = "{0} is required")]
[EmailAddress]
public string Email { get; set; }
[Display(Name = "Password")]
[Required(ErrorMessage = "{0} is required")]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "RememberMe")]
public bool RememberMe { get; set; }
}
public async Task OnGetAsync(string returnUrl = null)
{
if (!string.IsNullOrEmpty(ErrorMessage))
{
ModelState.AddModelError(string.Empty, ErrorMessage);
}
returnUrl ??= Url.Content("~/Books/List");
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
ReturnUrl = returnUrl;
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl ??= Url.Content("~/Books/List");
string WrongLoggin = _stringLocalizer["НеВерныйЛогин"].Value;
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
return RedirectToPage("./Lockout");
}
else
{
ModelState.AddModelError(string.Empty, WrongLoggin);
return Page();
}
}
// If we got this far, something failed, redisplay form
return Page();
}
}
}
How to translate text in .cs files, how to make it work?
[Display(Name = "How Translate With Text?")]
[Required(ErrorMessage = "How {0} Translate with Text?")]
Img Login Ru
Img Login En
I tried examples as for pages of controllers.
Created resources with the name LoginModel+InnerModel.en.resx and LoginModel+InnerModel.ru.resx.
But it did't give results.
P.S. Sorry for Google translate, but i need help.
P.S.2. Localization made on the example of this video
First you need to add AddDataAnnotationsLocalization in your Stratup,
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddRazorPages().AddDataAnnotationsLocalization();
Then you need to name your resource file like
Areas.Identity.Pages.Account.LoginModel+InputModel.en-US.resx
For any nested model in LoginModel, you need to use + instead of .
For the details you can see the doc:
DataAnnotations localization.

Controller not executing code (Blazor server-side)

My Goal Create a simple login form in order to authenticate and authorize the user in my Blazor Server-side app with Cookie Authentication.
My Issue Everything works... The EditForm passes the values to my Controller. The Controller validates the usercredentials. Then runs HttpContext.SignInAsync(claims) and returns Ok().
But the Cookie is not passed and the user is not Authenticate either.
What I have done
1. The EditForm, passes the userinputs to the DisplayLoginModel() on a ValidSubmit.
<div class="row">
<div class="col-8">
<EditForm Model="#userLogin" OnValidSubmit="OnValidLogin">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="mb-4 row">
<p class="col-sm-4 font-weight-bold">Email</p>
<div class="col-sm-8">
<InputText #bind-Value="userLogin.Email" class="form-control" />
</div>
</div>
<div class="mb-4 row">
<p class="col-sm-4 font-weight-bold">Password</p>
<div class="col-sm-8">
<InputText #bind-Value="userLogin.Password" class="form-control" />
</div>
</div>
<button class="btn btn-outline-primary col-sm-4" type="submit"><strong>Login EditForm</strong></button>
</EditForm>
</div>
</div>
2. The OnValidLogin Sends a request to the Form Controller
public DisplayLoginModel userLogin = new DisplayLoginModel();
private async Task OnValidLogin()
{
var requestMessage = new HttpRequestMessage()
{
Method = new HttpMethod("POST"),
RequestUri = new Uri("https://localhost:44370/Form"),
Content = JsonContent.Create(userLogin)
};
var client = httpfac.CreateClient();
var response = await client.SendAsync(requestMessage);
}
3. The Controller gets the user credentials from the displayloginModel and validets Ok().
[HttpPost]
public async Task<ActionResult> Post(DisplayLoginModel _userLogin)
{
if (_userLogin.Email == "this#Email.com")
{
ClaimsIdentity claimsIdentity = new ClaimsIdentity(new List<Claim>
{
new Claim(ClaimTypes.Role, "ActiveUser")
}, "auth");
ClaimsPrincipal claims = new ClaimsPrincipal(claimsIdentity);
await HttpContext.SignInAsync(claims);
return Ok();
}
else
{
return BadRequest();
}
}
4. Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
services.AddHttpContextAccessor();
services.AddAuthentication("Cookies").AddCookie(options =>
{
options.SlidingExpiration = true;
});
services.AddRazorPages();
services.AddServerSideBlazor();
}
And
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
Why is the Controller not signing the user in, what am I missing?
An image of the solution structure is seen right below:
Because Blazor Server uses websockets (Blazor circuits) to render the UI while on the controller, await HttpContext.SignInAsync(claims); returns a cookie header so the browser can be authorized on next page load. This means you are actually being authenticated server-side but not from the client-side as you have not reloaded the page context to update the cookies. There is a reason why the default Identity login uses MVC architecture for the authentication process. :)
My suggestion, switch to API-based authentication/authorization or use a traditional login in flow.

Session problem.Why "Continue shopping" does not work?

I have this view with some product list. List from different table
<form method="get">
<td class="button13"><button type="submit" asp-action="Buy" asp-route-id="#p.ProductId" asp-controller="Search">Buy</button></td>
<input type="hidden" name="returnUrl" value="#ViewContext.HttpContext.Request.PathAndQuery()" />
</form>
Then we go to form post to add some information about client. And then we will go to cart
Controller
public ViewResult Index(string returnUrl)
{
return View(new CartIndexViewModel
{
Cart = GetCart(),
ReturnUrl = returnUrl
});
}
public ActionResult AddToCart(string returnUrl,int priceCart,DateTime dateFromCart, int Tick,int Fli)
{//we are here after form post
Cart cart = GetCart();
cart.AddItem(1,priceCart,dateFromCart);
SaveCart(cart);
return RedirectToAction("Index", new { returnUrl });
}
private Cart GetCart()
{
Cart cart = HttpContext.Session.GetJson<Cart>("Cart") ?? new Cart();
return cart;
}
private void SaveCart(Cart cart)
{
HttpContext.Session.SetJson("Cart", cart);
}
Second View
#model Phone1.Models.ViewModels.CartIndexViewModel;
<h2>Your cart</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Quantity</th>
<th>Item</th>
<th class="text-right">Price</th>
<th class="text-right">Subtotal</th>
</tr>
</thead>
<tbody>
#foreach (var line in Model.Cart.Lines)
{
<tr>
<td class="text-center">#line.Quantity</td>
<td class="text-left">#line.PriceCart</td>
<td class="text-left">#line.DateFromCart.ToString("D")"</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<td colspan="3" class="text-right">Total:</td>
<td class="text-right">
#Model.Cart.ComputeTotalValue().ToString("c")
</td>
</tr>
</tfoot>
</table>
<div class="text-center">
<a class="btn btn-primary" href="#Model.ReturnUrl"><h3>Continue shopping</h3></a>
</div>
And Infrastructure files
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
namespace Phone1.Infrastructure
{
public static class SessionExtensions
{
public static void SetJson(this ISession session, string key, object value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T GetJson<T>(this ISession session, string key)
{
var sessionData = session.GetString(key);
return sessionData == null
? default(T) : JsonConvert.DeserializeObject<T>(sessionData);
}
}
}
And other Infrasructure`s file
using Microsoft.AspNetCore.Http;
namespace Phone1.Infrastructure
{
public static class UrlExtensions
{
public static string PathAndQuery(this HttpRequest request) =>
request.QueryString.HasValue
? $"{request.Path}{request.QueryString}"
: request.Path.ToString();
}
}
Startup
public class Startup
{
public Startup(IConfiguration configuration) =>
Configuration = configuration;
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<PhoneAppDbContext>(options =>
options.UseSqlServer(Configuration["Data:PhoneAppDb:ConnectionString"]));
services.AddMvc();
services.AddMemoryCache();
services.AddSession();
services.AddControllersWithViews(mvcOtions =>
{
mvcOtions.EnableEndpointRouting = false;
});
services.AddMvc()
.AddRazorRuntimeCompilation();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStatusCodePages();
app.UseStaticFiles();
app.UseSession();
app.UseMvc(routes => {
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "",
template: "{controller=SearchTicket}/{action=AddToCart}/{id?}");
routes.MapRoute(
name: "",
template: "{controller=SearchTicket}/{action=Index}/{id?}");
});
}
}
}
Model 1
namespace Phone1.Models.ViewModels
{
public class CartIndexViewModel
{
public Cart Cart { get; set; }
public string ReturnUrl { get; set; }
}
}
Model 2
using System;
using System.Collections.Generic;
using System.Linq;
namespace Phone1.Models
{
public class Cart
{
private List<CartLine> lineCollection = new List<CartLine>();
public virtual void AddItem(int quantity,int priceCart,DateTime dateFromCart)
{
CartLine line = lineCollection
.FirstOrDefault();
if (line == null)
{
lineCollection.Add(new CartLine
{
DateFromCart=dateFromCart,
PriceCart=priceCart,
Quantity = quantity
});
}
else
{
//line.Quantity += quantity;
}
}
public virtual void RemoveLine(int priceCart,DateTime dateFromCart) =>
lineCollection.RemoveAll();
public virtual int ComputeTotalValue() =>
lineCollection.Sum(e => e.PriceCart);
//* e.Quantity
public virtual void Clear() => lineCollection.Clear();
public virtual IEnumerable<CartLine> Lines => lineCollection;
}
public class CartLine
{
public int CartLineId { get; set; }
public DateTime DateFromCart { get; set; }
public int PriceCart { get; set; }
public int Quantity { get; set; }
}
}
All things add to cart, but <a class="btn btn-primary" href="#Model.ReturnUrl"><h3>Continue shopping</h3></a> does not work at all.It does not work even like link <a>.What is wrong?
There is no error message.
Controller
public ViewResult Index(string returnUrl)
{
return View(new CartIndexViewModel
{
Cart = GetCart(),
ReturnUrl = returnUrl
});
}
public ActionResult AddToCart(string returnUrl,int priceCart,DateTime dateFromCart, int Tick,int Fli)
{//we are here after form post
Cart cart = GetCart();
cart.AddItem(1,priceCart,dateFromCart);
SaveCart(cart);
return RedirectToAction("Index", new { returnUrl });
}
We go to Index method with returnUrl

MvC multiple submits diffrent columns same row

So this is the code, i have 2 submit buttons when i press "Start" I want it to send the Datetime.now to the start row, and when i press "Stop" i want it to send the Stop datetime.now to the column, this should be happening in the same row. And when i press Start again it should generate a new ID 2, etc. print the start date on the second row.
Exampel ID 1 : Start 2013-11-15 05:12 Slut : 2013-11-15 05:15
Greetings Patrik
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="editor-label">
#Html.LabelFor(model => model.Start)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Start, new { style = "display: none;", #Value = #DateTime.Now })
#Html.ValidationMessageFor(model => model.Start)
</div>
<p>
<input type="submit" name="#Html.NameFor(x => x.Command)" value="Start" formaction="/tider/create" />
</p>
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="editor-label">
#Html.LabelFor(model => model.Slut)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Slut, new { #Value = #DateTime.Now })
#Html.ValidationMessageFor(model => model.Slut)
</div>
<p>
<input type="submit" name="#Html.NameFor(x => x.Command)" value="Stop" />
</p>
}
</fieldset>
<div class="editor-label">
#Html.LabelFor(model => model.Slut)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Slut, new { #Value = #DateTime.Now })
#Html.ValidationMessageFor(model => model.Slut)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
controller
{
public class TiderController : Controller
{
private TiderDBContext db = new TiderDBContext();
//
// GET: /Tider/
public ActionResult Index()
{
return View(db.Tider.ToList());
}
//
// GET: /Tider/Details/5
public ActionResult Details(int id = 0)
{
ArbetsTider arbetstider = db.Tider.Find(id);
if (arbetstider == null)
{
return HttpNotFound();
}
return View(arbetstider);
}
//
// GET: /Tider/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Tider/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ArbetsTider arbetstider)
{
if (ModelState.IsValid)
{
db.Tider.Add(arbetstider);
db.SaveChanges();
}
return View(arbetstider);
}
//
// GET: /Tider/Edit/5
public ActionResult Edit(int id = 0)
{
ArbetsTider arbetstider = db.Tider.Find(id);
if (arbetstider == null)
{
return HttpNotFound();
}
return View(arbetstider);
}
//
// POST: /Tider/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(ArbetsTider arbetstider)
{
if (ModelState.IsValid)
{
db.Entry(arbetstider).State = EntityState.Modified;
return RedirectToAction("Index");
}
return View(arbetstider);
}
//
// GET: /Tider/Delete/5
public ActionResult Delete(int id = 0)
{
ArbetsTider arbetstider = db.Tider.Find(id);
if (arbetstider == null)
{
return HttpNotFound();
}
return View(arbetstider);
}
//
// POST: /Tider/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
ArbetsTider arbetstider = db.Tider.Find(id);
db.Tider.Remove(arbetstider);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
[HttpPost]
public ActionResult Start(ArbetsTider model)
{
using (var context = new TiderDBContext())
{
context.Tider.FirstOrDefault(x => x.ID == model.ID).Start = model.Start;
context.SaveChanges();
}
return View("Index");
}
[HttpPost]
public ActionResult Stop(ArbetsTider model)
{
using (var context = new TiderDBContext())
{
context.Tider.FirstOrDefault(x => x.ID == model.ID).Slut = model.Slut;
context.SaveChanges();
}
return View("Index");
}
}
}
model
public class ArbetsTider
{
public int ID { get; set; }
public DateTime Start { get; set; }
public DateTime Slut { get; set; }
}
public class TiderDBContext : DbContext
{
public DbSet<ArbetsTider> Tider { get; set; }
}
You need to use Ajax method to submit the one form partially without refreshing the whole page.
Try something like this:
First change like this(remove type='submit'):
#using (Html.BeginForm("Create", "Tider", FormMethod.Post, new { #id= "formStart" } ))
{
// html code
<input id="submittStartDate" name="#Html.NameFor(x => x.Command)" value="Start" class="submitButton" />
});
And
#using (Html.BeginForm("Stop", "Tider", FormMethod.Post, new { #id= "formStop" } ))
{
//html
<input id="stop" name="#Html.NameFor(x => x.Command)" value="Stop" class="submitButton" />
//html
});
Then add a function in javascript file:
$(document).ready(function () {
$("input.submitButton").click(function() {
SubmitForm(this);
});
});
function SubmitForm(input) {
var url = "";
var formData = "";
if(input[0].id == "formStart")
{
url = "../Tider/Create";
data = $('form#formStart').serialize();
}
else if(input[0].id == "formStop") {
url = "../Tider/Stop";
data = $('form#formStop').serialize();
}
$.ajax({
type: "POST",
url: url,
data: data,
success: function (result) {
// Do your stuff here
},
error: function () {
alert("Error in saving");
}
});
}
You need to change the return types of the C# methods Create and Stop to required type(I think you need int here) and retun that. And you will get the data "success" function of the Ajax call.