Get the Result from a list of Task - asynchronous

I know this has been asked before, but I simply cannot figure out how to do this right.
So, the below code is obviously wrong in the sense that I am awaiting something in a query.
// GET: /<controller>/
[HttpGet]
public new IActionResult Index()
{
var model = new List<Models.ViewModels.ApplicationUser.ListViewModel>();
model = _userManager.Users.Select(u => new Models.ViewModels.ApplicationUser.ListViewModel
{
Id = u.Id,
Email = u.Email,
Name = u.GivenName + " " + u.SurName,
RoleNames = await _userManager.GetRolesAsync(u)
}).ToList();
return View(model);
}
This makes the following error show: "the "await" operator can only be used within an async lambda expression".
So, I finalize the query first and I make the lambda async:
// GET: /<controller>/
[HttpGet]
public new IActionResult Index()
{
var model = new List<Models.ViewModels.ApplicationUser.ListViewModel>();
// get users first, so I don't have to async something in a Select
var users = _userManager.Users.ToList();
// make the lambda asyc
model = users.Select(async u => new Models.ViewModels.ApplicationUser.ListViewModel
{
Id = u.Id,
Email = u.Email,
Name = u.GivenName + " " + u.SurName,
RoleNames = await _userManager.GetRolesAsync(u)
}).ToList();
return View(model);
}
But then I get Cannot implicitly convert type 'System.Collections.Generic.List<System.Threading.Tasks.Task<Models.ViewModels.ApplicationUser.ListViewModel>>' to 'System.Collections.Generic.List<Models.ViewModels.ApplicationUser.ListViewModel>'
So basically (I guess) it says I have a list of Task of which I should get the result. But how do I get the result from this Task? Or better: what is the best way to go about this?
I've checked this and this and this without getting closer.

Your variable named model is of the type List<Task<ApplicationUser>>. To get a List<ApplicationUser> you just need to await all of the tasks. Also, right now the call to get all users is the blocking variant you can switch that out for ToListAsync. Try this instead:
[HttpGet]
public async Task<IActionResult> Index() {
var model = new List<Models.ViewModels.ApplicationUser.ListViewModel>();
// get users first, so I don't have to async something in a Select
var users = await _userManager.Users.ToListAsync();
// make the lambda asyc
modelTasks = users.Select(async u => new Models.ViewModels.ApplicationUser.ListViewModel {
Id = u.Id,
Email = u.Email,
Name = u.GivenName + " " + u.SurName,
RoleNames = await _userManager.GetRolesAsync(u)
}).ToList();
var users = await Task.WhenAll(modelTasks);
return View(users);
}

Related

Get value from IActionResult

I have Controller whit some endpoints Task<IActionResult> MyCustomEndpoint which is returning return Ok(CustomDataType). Returned datas are in JSON fromat.
Now I want to call that Endpoint from other Controller like var resp = myController.MyCustomEndpoint, where resp becomes IActionResult. The problem is that resp now doesn't return only datas anymore, but all of those fields as seen on image.
My question is, how to access and return only Value field, because resp.Value is not working.
Thanks for help.
You have to convert to as ObjectResult
public async Task GetFormSummary_ItShouldReturnSingleForm_NotNull()
{
var formId = new Guid("5EF685E7-1167-4226-7F5E-08D9009544A3");
var mockFormService = new Mock<IFormService>();
mockFormService.Setup(x => x.GetAsync(formId).Result)
.Returns(GetTestForm());
// Inject
var formController = new FormController(_logger, mockFormService.Object);
// Act
var result = (await formController.GetAsync(formId)) as ObjectResult;
// Assert
Assert.IsAssignableFrom<FormViewModel>(result.Value);
}

Invalid object name 'AspNetRoleClaims' exception when logging in

So I implemented Identity for my core project. I have successfully completed my Registration. So while trying to login using the _signInManager.PasswordSignInAsync I am getting the exception Invalid object name 'AspNetRoleClaims'.
I know this is because the AspNetRoleClaims table is not present in my database. But idont know the structure of this table nor do I know how to create it automatically like in mvc.
Can somebody enlighten me why this table is used. Or at least what is the expected structure.
public async Task<IActionResult> RegisterSubmit(Registermodel rm)
{
if (rm.role == "" || rm.role.Trim() == "-1")
{
return View();
}
else
{
var user = new ApplicationUser { UserName = rm.username, Email = rm.username, DeptName = rm.role };
var result = await _userManager.CreateAsync(user, rm.Password);
if (result.Succeeded)
{
_userManager.GenerateEmailConfirmationTokenAsync(user);
await _signInManager.SignInAsync(user, isPersistent: false);
var roleexists = await _roleManager.RoleExistsAsync(rm.role);
if (!roleexists)
{
var role = new IdentityRole();
role.Name = rm.role;
await _roleManager.CreateAsync(role);
}
await _userManager.AddToRoleAsync(user, rm.role);
user.Claims.Add(new IdentityUserClaim<string>
{
ClaimType = "ProductUploadRequest",
ClaimValue = "Allow"
});
}
return View("Login");
}
}
This is my login method.
public async Task<IActionResult> Login(LoginIdentityModel lim)
{
var result = await _signInManager.PasswordSignInAsync(lim.username, lim.password,false, lockoutOnFailure: false); //exception comes here
if (result.Succeeded)
{
var user = await _userManager.GetUserAsync(HttpContext.User);
UserProfileInfo userProfileInfo = new UserProfileInfo();
userProfileInfo.UserId = new Guid(user.Id);
userProfileInfo.FirstName = "test";
userProfileInfo.UserName = lim.username;
userProfileInfo.LastVisit = DateTime.Now;
string query2 = "select ud.UserId,dp.Id DeptId,dp.Name DeptName,rd.Id RoleId,rd.Name RoleName,ud.[ReadWrite] from UserInDepartment ud inner join Department dp on ud.DeptId=dp.Id inner join RolesInDepartment rd on dp.Id=rd.DeptId and ud.RoleId=rd.Id where ud.UserId='" + user.Id + "' and dp.IsEnable=1 and rd.IsEnable=1 and ud.IsEnable=1";
var userProfile = await _departMentalContext.UserProfiles.FromSql(query2).SingleOrDefaultAsync();
if (userProfile != null)
{
Dictionary<int, string> deptValues = new Dictionary<int, string>() { { userProfile.DeptId, userProfile.DeptName } };
userProfileInfo.Dept = deptValues;
Dictionary<int, string> roleValues = new Dictionary<int, string>() { { userProfile.RoleId, userProfile.RoleName } };
userProfileInfo.Role = roleValues;
userProfileInfo.ReadOrWrite = userProfile.ReadWrite;
HttpContext.Session.SetObject(UserProfileSessionName, userProfileInfo);
}
return View("/Home/DashBoard");
}
return View();
}
As you are using EF, you should be able to update your model database.
You can use CLI command (learn.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet).
Or if you are using Visual Studio, in the package manager console, you can execute those commands :
Add-Migration "init"
Update-Database
Commands allows you tu update table in your database. Also, it will create migrations files, which are a "picture" of your models. When the command Update-Database is executed, it loads the last migration file.

How to get a Json Response after saving a data in ASP.Net

how can I get a response after I created a data? So I want is when is saves. it show it's response, maybe in messagebox? Is it possible do it?
This is my controller code in saving..
[HttpPost]
[ValidateAntiForgeryToken]
public async System.Threading.Tasks.Task<ActionResult> Create(FormCollection formCollection, string fn, string ln , ParentModel apsp)
{
string username = "sa";
string apiKey = "sa";
string baseUrl = "https://sandbox-api.paysimple.com";
var settings = new PaySimpleSdk.Models.PaySimpleSettings(apiKey, username, baseUrl);
var paymentService = new PaymentService(settings);
fn = apsp.Customer.FirstName;
ln = apsp.Customer.LastName;
string street1 = apsp.Customer.BillingAddress.StreetAddress1;
string street2 = apsp.Customer.BillingAddress.StreetAddress2;
string city = apsp.Customer.BillingAddress.City;
Enum statecode = apsp.Customer.BillingAddress.StateCode;
Enum country = apsp.Customer.BillingAddress.Country;
string zipcode = apsp.Customer.BillingAddress.ZipCode;
string credit = apsp.CreditCard.CreditCardNumber;
string expir = apsp.CreditCard.ExpirationDate;
Enum issuer = apsp.CreditCard.Issuer;
decimal amount = apsp.Payment.Amount;
string ccv = apsp.Payment.Cvv;
var customerPayment = new NewCustomerPayment<CreditCard>
{
Customer = new Customer()
{
FirstName = fn,
LastName = ln,
BillingAddress = new Address
{
StreetAddress1 = street1,
StreetAddress2 = street2,
City = city,
StateCode = (StateCode)statecode,
Country = (CountryCode)country,
ZipCode = zipcode
}
},
Account = new CreditCard
{
CreditCardNumber = credit,
ExpirationDate = expir,
Issuer = (Issuer)issuer
},
Payment = new Payment
{
Amount = amount,
Cvv = ccv
}
};
var newCustomerPayment = await paymentService.CreateNewCustomerPaymentAsync(customerPayment);
return RedirectToAction("Index");
}
The function of creating a data is from the SDK and the model itself
You have 2 options:
Create action should return JsonResult instead of redirect. But you will need to use AJAX when calling Create action.:
public async System.Threading.Tasks.Task<ActionResult> Create(FormCollection formCollection, string fn, string ln , ParentModel apsp)
{
/// your code for creating object
return Json(newCustomerPayment, JsonRequestBehavior.AllowGet);
}
on the client side use Ajax.BeginForm instead of Html.BeginForm
using (Ajax.BeginForm("Create", Home , new AjaxOptions { HttpMethod = "POST", OnSuccess = "customerPaymentCreatedSuccess" }))
{
}
<script>
function customerPaymentCreatedSuccess(response)
{
alert(JSON.stringify(response, null, 4));
}
</script>
Use Post/Redirect/Get pattern. Once new payment is created, store it in TempData
and return redirect as you currently do:
TempData["newCustomerPayment"] = newCustomerPayment;
return RedirectToAction("Index");
Then in Index Action check if there is anything in TempData and if there is, pass it to the view
public ActionResult Index()
{
var customerPayment = TempData["newCustomerPayment"] as NewCustomerPayment;
if(customerPayment != null)
{
ViewBag.customerPayment = customerPayment;
}
//other code..
}
Index view - generate JavaScript code to display customerPayment:
#{var customerPayment = ViewBag.customerPayment as NewCustomerPayment;}
#if(customerPayment != null)
{
<script>
alert("#Html.Raw(JsonConvert.SerializeObject(customerPayment ))");
</script>
}
To show an feedback of your of your operation you could return a JsonResult from your method and make the call and create the message box browser-side via Javascript.
Actions to take
1)change ActionResult to JsonResult in method definition
public async System.Threading.Tasks.Task<JsonResult> Create(FormCollection formCollection, string fn, string ln , ParentModel apsp)
2)change the return to something like:
return this.Json(message)
3)make your call to the method using ajax an create the message box on the callback method

asp.net web api 2 LINQ to Entities does not recognize the method

I want to invoke method durning mapping my domain class to DTO class but after many tries with LINQ to Entities or LINQ to objects i have failed and i'm getting weird different errors. Actulal error is just a "LINQ to Entities does not recognize the method 'System.String ResizeToLogoImage(System.String)' method, and this method cannot be translated into a store expression.".
Mapping method:
public async Task<SingleCategory> SingleCategoryMapping(EventerApiContext context, int id)
{
var category = await context.Category.Select(c => new SingleCategory
{
CategoryId = c.CategoryId,
CategoryName = c.CategoryName,
CityId = c.CityId,
Events = context.Event.ToList().Where(e=>e.CategoryId == id).Select(e=> new EventForSingleCategory
{
EventId = e.EventId,
EventName = e.EventName,
EventLogo = ImageProcessor.ResizeToLogoImage(e.EventDetail.EventImage.EventImageBase64)
}).ToList()
}).SingleOrDefaultAsync(c => c.CategoryId == id);
return category;
}
Method to be invoked.
public static string ResizeToLogoImage(string base64String)
{
if (base64String == null)
{
return "NULL";
}
var imageToResize = Base64ToImage(base64String);
var resizedImage = ScaleImage(imageToResize, 50, 50);
return ImageToBase64(resizedImage, imageToResize.RawFormat);
}
I know error is appearing during EventLogo property mapping but i have no more idea what to do.
Try to get the data first, before you do the Select statement. I suspect that it is trying to execute ResizeToLogoImage on the database :)

Kendo dropdownlist produces TypeError: n.slice is not a function

Do I need to define the schema? If so, what should that look like? My searches for this seem to only turn up js solutions, I'm looking for the syntax to define it in the editortemplate.
Shared/editortemplate:
#(
Html.Kendo().DropDownList()
.Name("SearchFunction")
.DataTextField("SearchFunctionDesc")
.DataValueField("SearchFunctionCode")
.DataSource(source =>
{
source.Read(read => {
read.Action("GetSearchFunctions", "User");
});
})
.OptionLabel("--Select a Search Function--")
.AutoBind(false)
)
In the controller:
public JsonResult GetSearchFunctions([DataSourceRequest] DataSourceRequest request)
{
var searchFuncs = AdminService.GetSearchFunctions();
DataSourceResult result = searchFuncs.ToDataSourceResult(request);
return Json(result, JsonRequestBehavior.AllowGet);
}
And then my Dapper db query:
var result = new List<SearchFunction>();
using (var conn = new OracleConnection(DatabaseConnectionString))
{
conn.Open();
string query = "select FUNCTION_ID, SEARCH_FUNCTION_CD, " +
"SEARCH_FUNCTION_DESC, IS_ACTIVE " +
"from TBL_SEARCH_FUNCTIONS ";
result = conn.Query(query)
.Select(s => new SearchFunction
{
FunctionId = (int)s.FUNCTION_ID,
SearchFunctionCode = s.SEARCH_FUNCTION_CD,
SearchFunctionDesc = s.SEARCH_FUNCTION_DESC,
Active = s.IS_ACTIVE
}).ToList<SearchFunction>();
conn.Close();
return result;
}
Rewrite your controller method like this:
public JsonResult GetSearchFunctions()
{
var searchFuncs = cmsViewAdminService.GetSearchFunctions();
return Json(searchFuncs, JsonRequestBehavior.AllowGet);
}
That should simplify that method as you don't need the DataSourceRequest (as #CSharper mentioned in the comment). Kendo DropDownLists, unlike the grids, don't require the DataSourceRequest class. This way, you can call the same JsonResult from a jQuery Ajax method if you needed to do so.
You need to return a pure collection from json something that looks like that
{[
{"Id":2,"Name":"some"},
{"Id":3,"Name":"som2"}
]}
If you use ModelView and lambda then you might also try to the code below:
Assume you have a city dropdownlist retrieving data from reference table (populated to CityViewModel):
public JsonResult GetCities()
{
var dataContext = new EFDbContext();
var cities = dataContext.Cities.Select(c => new CityViewModel
{
ID = c.ID,
Name = c.Name
});
return Json(cities, JsonRequestBehavior.AllowGet);
}

Resources