FormatException and ArgumentException errors - visual-studio

I get these errors in Visual Studio in an ASP.NET Core 2.1 application while attempting to change identity from string to long. Has anyone else run into these errors?
An unhandled exception occurred while processing the request.
FormatException: Input string was not in a correct format.
System.Number.StringToNumber(ReadOnlySpan str, NumberStyles
options, ref NumberBuffer number, NumberFormatInfo info, bool
parseDecimal) ArgumentException: 81d1aa6c-b70a-4d64-a62a-e177d79b944e
is not a valid value for Int64. Parameter name: value
System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext
context, CultureInfo culture, object value)

For changing Identity primary key from string to long, follow steps below:
Add ApplicationUser.cs
public class ApplicationUser:IdentityUser<long>
{
}
Modify ApplicationDbContext
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, IdentityRole<long>, long>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
Modify Startup.cs
services.AddDefaultIdentity<ApplicationUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Modify _LoginPartial.cshtml from IdentityUser to ApplicationUser
#using Microsoft.AspNetCore.Identity
#inject SignInManager<ApplicationUser> SignInManager
#inject UserManager<ApplicationUser> UserManager
#if (SignInManager.IsSignedIn(User))
{
<form asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="#Url.Action("Index", "Home", new { area = "" })" method="post" id="logoutForm" class="navbar-right">
<ul class="nav navbar-nav navbar-right">
<li>
<a asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello #UserManager.GetUserName(User)!</a>
</li>
<li>
<button type="submit" class="btn btn-link navbar-btn navbar-link">Logout</button>
</li>
</ul>
</form>
}
else
{
<ul class="nav navbar-nav navbar-right">
<li><a asp-area="Identity" asp-page="/Account/Register">Register</a></li>
<li><a asp-area="Identity" asp-page="/Account/Login">Login</a></li>
</ul>
}

Related

Cannot download files in .Net 6

I have an MVC .Net Core 2.1 application. It has an action that generates a .csv file and returns it to download. Now, as this .Net version is not supported, I created a new application with .NET 6, and moved there my controllers, views etc. from the old application. Now for some reason download does not work. The execution does not even reach the action, and I get this error:
No webpage was found for the web address:
https://localhost:44398/Reports/InventoryReportAsync HTTP ERROR 404
So it is looking for the view by the action name, but this view obviously does not exist.
Here is my code:
_Layout.cshtml
<div class="dropdown">
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Reports</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" asp-controller="Reports" asp-action="InventoryReportAsync">Inventory Report</a></li>
<li><a class="dropdown-item" asp-controller="Reports" asp-action="ItemReorderReportAsync">Item Reorder Report</a></li>
<li><a class="dropdown-item" asp-controller="Reports" asp-action="OrderHistoryReport">Order History Report</a></li>
</ul>
</div>
ReportsController.cs
public async Task<IActionResult> InventoryReportAsync()
{
try
{
List<InventoryReportDto> reportModel = await _itemRepository.GetInventoryReportDtosAsync();
return await Export<InventoryReportDto, InventoryReportCsvMap>(reportModel, "InventoryReport.csv");
}
catch (Exception ex)
{
return StatusCode(500, new { ex.Message });
}
}
protected async Task<IActionResult> Export<T, M>(List<T> exportModel, string fileName) where T : class where M : ClassMap
{
MemoryStream stream = new MemoryStream();
StreamWriter streamWriter = new StreamWriter(stream)
{
AutoFlush = true
};
CsvWriter csv = new CsvWriter(streamWriter, CultureInfo.InvariantCulture);
csv.Context.RegisterClassMap<M>();
csv.WriteRecords(exportModel);
await csv.FlushAsync();
stream.Position = 0;
return File(stream, "application/octet-stream", fileName);
}
ADDED:
Program.cs
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
This is how it looked in .Net 2.1:
Startup.cs
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
I posted this question elsewhere, and got an answer here:
https://learn.microsoft.com/en-us/answers/questions/874470/cannot-download-files-in-net-6.html
I just needed to remove the "Async" suffix from the action name here:
<div class="dropdown">
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Reports</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" asp-controller="Reports" asp-action="InventoryReport">Inventory Report</a></li>
<li><a class="dropdown-item" asp-controller="Reports" asp-action="ItemReorderReport">Item Reorder Report</a></li>
<li><a class="dropdown-item" asp-controller="Reports" asp-action="OrderHistoryReport">Order History Report</a></li>
</ul>
</div>

Spring Boot + Thymeleaf: combine filtering and pagination for list

Good evening all,
I'm learning Thymeleaf and web applications in general right now, and for starters, I'm trying to implement a web service with a page where you can view all registered users and filter them.
Since I want some pagination, I have two forms on this page:
a group of buttons linking to the first, previous, next, and last page
a form with various options for filtering, e.g. "username contains" or "min / max age"
My controller looks like this:
#RequestMapping("/users/all")
String showSearchPage(#RequestParam(value="page", required=false, defaultValue = "0") int page,
#CurrentSecurityContext(expression="authentication?.name") String username,
Model model) {
Page<User> userPage = userService.filterUsers(username, "", 0, 100, PageRequest.of(page, 10));
model.addAttribute("userPage", userPage);
model.addAttribute("pageNr", page);
return "users.html";
}
As you can see, I only implemented the buttons yet and always filter for some default values. (The username parameter makes sure that the currently logged in user isn't finding themself in the list.) My button form looks like that:
<form class="button" th:action="#{/users/all}" method="POST">
<button th:disabled="${pageNr == 0}" type="submit"
class="btn btn-primary"
name="page" th:value="0"><<</button>
<button th:disabled="${pageNr == 0}" type="submit"
class="btn btn-primary"
name="page" th:value="${pageNr - 1}"><</button>
<button th:disabled="${pageNr == userPage.getTotalPages - 1}" type="submit"
class="btn btn-primary"
name="page" th:value="${pageNr + 1}">></button>
<button th:disabled="${pageNr == userPage.getTotalPages - 1}" type="submit"
class="btn btn-primary"
name="page" th:value="${userPage.getTotalPages - 1}">>></button>
</form>
So I'm using the request parameter page to only show the requested page.
Now that I'm about to implement the filtering, my first approach would be adding the form to my HTML, and adding some #ModelAttribute FilterForm filterForm to my controller to be able to get the submitted filter values and use them to retrieve the filtered user list. However, when thinking about it, I found the problem that both forms would only submit their own content, and the controller would only get one of both. Therefore, after filtering users, I would inadvertedly revert back to the full user list when changing pages.
What would be the best approach here to make sure that both functions, filtering and pagination, work together properly?
Thanks in advance!
I'd go with HTTP GET method instead of POST. Why so? Reading users is an idempotent and safe operation. The applied filter and page number can be easily bookmarked in that case.
For filters, you can just add more params. Nothing bad about that.
Make it a bit more RESTful. "/users/all" is unnecessary. "/users" should be enough.
#GetMapping("/users")
String showSearchPage(#RequestParam(value="page", required=false, defaultValue = "0") int page,
#RequestParam("minAge") Optional<Integer> minAge,
#RequestParam("maxAge") Optional<Integer> maxAge,
#CurrentSecurityContext(expression="authentication?.name") String username,
Model model) {
// Apply filters too...
Page<User> userPage = userService.filterUsers(username, "", 0, 100, PageRequest.of(page, 10));
model.addAttribute("userPage", userPage);
model.addAttribute("pageNr", page);
model.addAttribute("nextPage", getPageWithFilterUrl(page + 1, minAge, maxAge));
model.addAttribute("previousPage", getPageWithFilterUrl(page - 1, minAge, maxAge));
return "users.html";
}
To preserve filter while moving back and forth:
private String getPageWithFilterUrl(int page, Optional<Integer> minAge, Optional<Integer> maxAge) {
String defaultNextPageUrl = "/users?page=" + page;
String withMinAge = minAge.map(ma -> defaultNextPageUrl + "&minAge=" + ma).orElse(defaultNextPageUrl);
String withMaxAge = maxAge.map(ma -> withMinAge + "&maxAge=" + ma).orElse(withMinAge);
return withMaxAge;
}
I think the answer is not given here yet. I have the same problem now. I am trying in my project with redirectAttributes.addFlashAttribute("searchProductItemDTO", searchProductItemDTO);
But the problem comes when clicking on the Next/Previous buttons - clicking them does not take into account the search criteria.
Here is my total solution:
1) Pay attention here to the JpaSpecificationExecutor<ItemEntity>
#Repository
public interface AllItemsRepository extends
PagingAndSortingRepository<ItemEntity, Long>, JpaSpecificationExecutor<ItemEntity>{
}
2) Pay attention here to the CriteriaBuilder
public class ProductItemSpecification implements Specification<ItemEntity> {
private final SearchProductItemDTO searchProductItemDTO;
private final String type;
public ProductItemSpecification(SearchProductItemDTO searchProductItemDTO, String type) {
this.searchProductItemDTO = searchProductItemDTO;
this.type = type;
}
#Override
public Predicate toPredicate(Root<ItemEntity> root,
CriteriaQuery<?> query,
CriteriaBuilder cb) {
Predicate predicate = cb.conjunction();
predicate.getExpressions().add(cb.equal(root.get("type"), type));
if (searchProductItemDTO.getModel() != null && !searchProductItemDTO.getModel().isBlank()) {
Path<Object> model = root.get("model");
predicate.getExpressions().add(
//!!!!! when we have two relationally connected tables
// cb.and(cb.equal(root.join("model").get("name"), searchProductItemDTO.getModel()));
//when all fields are from the same table ItemEntity:::: the like works case insensitive
cb.and(cb.like(root.get("model").as(String.class), "%" + searchProductItemDTO.getModel() + "%"))
);
}
if (searchProductItemDTO.getMinPrice() != null) {
predicate.getExpressions().add(
cb.and(cb.greaterThanOrEqualTo(root.get("sellingPrice"),
searchProductItemDTO.getMinPrice()))
);
}
if (searchProductItemDTO.getMaxPrice() != null) {
predicate.getExpressions().add(
cb.and(cb.lessThanOrEqualTo(root.get("sellingPrice"),
searchProductItemDTO.getMaxPrice()))
);
}
return predicate;
}
}
3) Pay attention here to the this.allItemsRepository.findAll default usage
//Complicated use
public Page<ComputerViewGeneralModel> getAllComputersPageableAndSearched(
Pageable pageable, SearchProductItemDTO searchProductItemDTO, String type) {
Page<ComputerViewGeneralModel> allComputers = this.allItemsRepository
.findAll(new ProductItemSpecification(searchProductItemDTO, type), pageable)
.map(comp -> this.structMapper
.computerEntityToComputerSalesViewGeneralModel((ComputerEntity) comp));
return allComputers;
}
4) Pay attention here to the redirectAttributes.addFlashAttribute
#Controller
#RequestMapping("/items/all")
public class ViewItemsController {
private final ComputerService computerService;
#GetMapping("/computer")
public String viewAllComputers(Model model,
#Valid SearchProductItemDTO searchProductItemDTO,
#PageableDefault(page = 0,
size = 3,
sort = "sellingPrice",
direction = Sort.Direction.ASC) Pageable pageable,
RedirectAttributes redirectAttributes) {
if (!model.containsAttribute("searchProductItemDTO")) {
model.addAttribute("searchProductItemDTO", searchProductItemDTO);
}
Page<ComputerViewGeneralModel> computers = this.computerService
.getAllComputersPageableAndSearched(pageable, searchProductItemDTO, "computer");
model.addAttribute("computers", computers);
redirectAttributes.addFlashAttribute("searchProductItemDTO", searchProductItemDTO);
return "/viewItems/all-computers";
}
5) Pay attention here to all the search params that we add in the html file, in the 4 sections where pagination navigation
<main>
<div class="container-fluid">
<div class="container">
<h2 class="text-center text-white">Search for offers</h2>
<form
th:method="GET"
th:action="#{/items/all/computer}"
th:object="${searchProductItemDTO}"
class="form-inline"
style="justify-content: center; margin-top: 50px;"
>
<div style="position: relative">
<input
th:field="*{model}"
th:errorclass="is-invalid"
class="form-control mr-sm-2"
style="width: 280px;"
type="search"
placeholder="Model name case Insensitive..."
aria-label="Search"
id="model"
/>
<input
th:field="*{minPrice}"
th:errorclass="is-invalid"
class="form-control mr-sm-2"
style="width: 280px;"
type="search"
placeholder="Min price..."
aria-label="Search"
id="minPrice"
/>
<input
th:field="*{maxPrice}"
th:errorclass="is-invalid"
class="form-control mr-sm-2"
style="width: 280px;"
type="search"
placeholder="Max price..."
aria-label="Search"
id="maxPrice"
/>
</div>
<button class="btn btn-outline-info my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
<h2 class="text-center text-white mt-5 greybg" th:text="#{view_all_computers}">.........All
Computers.......</h2>
<div class="offers row mx-auto d-flex flex-row justify-content-center .row-cols-auto">
<div
th:each="c : ${computers}" th:object="${c}"
class="offer card col-sm-2 col-md-3 col-lg-3 m-2 p-0">
<div class="card-img-top-wrapper" style="height: 20rem">
<img
class="card-img-top"
alt="Computer image"
th:src="*{photoUrl}">
</div>
<div class="card-body pb-1">
<h5 class="card-title"
th:text="' Model: ' + *{model}">
Model name</h5>
</div>
<ul class="offer-details list-group list-group-flush">
<li class="list-group-item">
<div class="card-text"><span th:text="'* ' + *{processor}">Processor</span></div>
<div class="card-text"><span th:text="'* ' + *{videoCard}">Video card</span></div>
<div class="card-text"><span th:text="'* ' + *{ram}">Ram</span></div>
<div class="card-text"><span th:text="'* ' + *{disk}">Disk</span></div>
<div th:if="*{!ssd.isBlank()}" class="card-text"><span th:text="'* ' + *{ssd}">SSD</span></div>
<div th:if="*{!moreInfo.isBlank()}" class="card-text"><span th:text="'* ' + *{moreInfo}">More info</span>
</div>
<div class="card-text"><span th:text="'We sell at: ' + *{sellingPrice} + ' лв'"
style="font-weight: bold">Selling price</span></div>
</li>
</ul>
<div class="card-body">
<div class="row">
<a class="btn btn-link"
th:href="#{/items/all/computer/details/{id} (id=*{itemId})}">Details</a>
<th:block sec:authorize="hasRole('ADMIN') || hasRole('EMPLOYEE_PURCHASES')">
<a class="btn btn-link alert-danger"
th:href="#{/pages/purchases/computers/{id}/edit (id=*{itemId})}">Update</a>
<form th:action="#{/pages/purchases/computers/delete/{id} (id=*{itemId})}"
th:method="delete">
<input type="submit" class="btn btn-link alert-danger" value="Delete"></input>
</form>
</th:block>
</div>
</div>
</div>
</div>
<div class="container-fluid row justify-content-center">
<nav>
<ul class="pagination">
<li class="page-item" th:classappend="${computers.isFirst()} ? 'disabled' : ''">
<a th:unless="${computers.isFirst()}"
class="page-link"
th:href="#{/items/all/computer(size=${computers.getSize()},page=0,model=${searchProductItemDTO.getModel()}, minPrice=${searchProductItemDTO.getMinPrice()},maxPrice=${searchProductItemDTO.getMaxPrice()})}">First</a>
</li>
</ul>
</nav>
<nav>
<ul class="pagination">
<li class="page-item" th:classappend="${computers.hasPrevious() ? '' : 'disabled'}">
<a th:if="${computers.hasPrevious()}"
class="page-link"
th:href="#{/items/all/computer(size=${computers.getSize()},page=${computers.getNumber() - 1},model=${searchProductItemDTO.getModel()}, minPrice=${searchProductItemDTO.getMinPrice()},maxPrice=${searchProductItemDTO.getMaxPrice()})}">Previous</a>
</li>
</ul>
</nav>
<nav>
<ul class="pagination">
<li class="page-item" th:classappend="${computers.hasNext() ? '' : 'disabled'}">
<a th:if="${computers.hasNext()}"
class="page-link"
th:href="#{/items/all/computer(size=${computers.getSize()},page=${computers.getNumber() + 1},model=${searchProductItemDTO.getModel()}, minPrice=${searchProductItemDTO.getMinPrice()},maxPrice=${searchProductItemDTO.getMaxPrice()})}">Next</a>
</li>
</ul>
</nav>
<nav>
<ul class="pagination">
<li class="page-item" th:classappend="${computers.isLast()} ? 'disabled' : ''">
<a th:unless="${computers.isLast()}"
class="page-link"
th:href="#{/items/all/computer(size=${computers.getSize()},page=${computers.getTotalPages()-1},model=${searchProductItemDTO.getModel()},minPrice=${searchProductItemDTO.getMinPrice()},maxPrice=${searchProductItemDTO.getMaxPrice()})}">Last</a>
</li>
</ul>
</nav>`enter code here`
</div>
</div>
</main>

RequestMethod.GET not getting envoked

My code looks as follows:
#Controller
public class ImporterErrorsController {
#RequestMapping(value = "importerErrors", method = RequestMethod.GET)
public String importerErrors(WebRequest webRequest, Model model) {
return "importerErrors";
}
}
And
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li class="active"><a th:href="#{/importerErrors}">Errors</a></li>
</ul>
</div>
For some reason when I click the errors button in the navbar, the method importErrors does not get invoked. I have successfully run some POST methods inside a form but for some reason i cannot get the GET method to get invoked. Additionally, I managed to do something similar in a different project.
Please let me know if I am doing something wrong.

How to set the login/logout link visible/invisible with Thymeleaf?

I am a beginner in Spring Framework. I try to make login and logout Thymeleaf pages. Below codes are the Spring Boot login/logout files with Thymeleaf.
First, Login Controllers codes
#Autowired
private HttpSession userSession;
#Autowired
private UserService userService;
#RequestMapping("/users/login")
public String login(LoginForm loginForm) {
return "users/login";
}
#RequestMapping(value="/users/login", method = RequestMethod.POST)
public String loginPage(#Valid LoginForm loginForm, BindingResult bindingResult) {
if(bindingResult.hasErrors()) {
userSession.setAttribute("blogLogin", false);
System.out.println("Wrong Input!!");
return "users/login";
}
if(!userService.authenticate(loginForm.getUsername(), loginForm.getPassword())) {
userSession.setAttribute("blogLogin", false);
System.out.println("login failed!!");
return "users/login";
}
userSession.setAttribute("blogLogin", true);
System.out.println("Login succesfully.");
return "redirect:/";
}
And the layout.html codes using thymeleaf.
<header th:fragment="site-header" th:remove="tag">
<header>
<a href="index.html" th:href="#{/}">
<img src="../public/img/site-logo.png" th:src="#{/img/site-logo.png}" />
</a>
Home
Log in
Log out
Register
Users
Posts
Write Post
<div id="logged-in-info"><span>Hello, <b>(user)</b></span>
<form method="post" th:action="#{/users/logout}">
<input type="submit" value="Log out"/>
</form>
</div>
</header>
</header>
The problem is I have no idea how to make login/logout link toggling codes using th:if statement of thymeleaf. As you know login link and logout link can not be displayed simultaneously.
you can check whether user is authenticated or anonymous like below and can make decisions.
<div sec:authorize="#{isAuthenticated()}">
<a th:href="#{/logout}">Log out</a>
</div>
<div sec:authorize="#{isAnonymous()}">
<a th:href="#{/login}">Log in</a>
</div>

Razor Syntax Not working the way I expected

having some trouble with my razor syntax
gives a Parsor error saying that
The foreach block is missing a closing "}" character
<ul>
#{var client = "null";}
#foreach (var instance in Model)
{
if (instance.tbl_Policy.tbl_Client.txt_clientName != client)
{
client = instance.tbl_Policy.tbl_Client.txt_clientName;
</ul><h1>#client</h1>
<ul>
}
<li>
#instance.tbl_Policy.txt_policyNumber -
Assigned to : #instance.aspnet_Membership.aspnet_User.UserName
#instance.ATLCheckType.Question
<button type="button" rel="<%:instance.ATLCheckInstanceId.ToString()%>">DelFiled</button>
<button type="button" rel="<%:instance.ATLCheckInstanceId.ToString()%>">DelLineItem</button>
</li>
}
</ul>
Razor cannot handle imbalanced HTML tags in code blocks.
Change your if block to treat the imbalanced tags as plain text:
if (instance.tbl_Policy.tbl_Client.txt_clientName != client)
{
client = instance.tbl_Policy.tbl_Client.txt_clientName;
#:</ul><h1>#client</h1>
#:<ul>
}
The code should be refactored to correctly support balanced tags
#foreach (var groupedClient in Model.GroupBy(i => i.tbl_Policy.tbl_Client.txt_clientName))
{
<ul>
<h1>#groupedClient.Key</h1>
foreach(var instance in groupedClient)
{
<li>
#instance.tbl_Policy.txt_policyNumber -
Assigned to : #instance.aspnet_Membership.aspnet_User.UserName
#instance.ATLCheckType.Question
<button type="button" rel="#instance.ATLCheckInstanceId.ToString()">DelFiled</button>
<button type="button" rel="#instance.ATLCheckInstanceId.ToString()">DelLineItem</button>
</li>
}
</ul>
}
What's with all of the <%: %> stuff in there? You need to use the # syntax.
<ul>
#{var client = "null";}
#foreach (var instance in Model)
{
if (instance.tbl_Policy.tbl_Client.txt_clientName != client)
{
client = instance.tbl_Policy.tbl_Client.txt_clientName;
</ul><h1>#client</h1>
<ul>
}
<li>
#instance.tbl_Policy.txt_policyNumber -
Assigned to : #instance.aspnet_Membership.aspnet_User.UserName
#instance.ATLCheckType.Question
<button type="button" rel="#instance.ATLCheckInstanceId.ToString()">DelFiled</button>
<button type="button" rel="#instance.ATLCheckInstanceId.ToString()">DelLineItem</button>
</li>
}
</ul>

Resources