MCV C# web-service with POST and two variables - c#

i am kinda new with the web services regarding to POST and i want to save the userId that i get from Owin and the id_cd in the favorite table. The webservice posted below is working however there is not need from me to get the return UserProvider back. The whole section ListAspNetUserLogins ... etc. is not needed but i can't seem to find a POST that allows me to add the two variables. What do i need to change to still have the two variables come in and get rid of the return UserProvider etc.
[Route("api/User/PostUserFavorite/{id_cd}/{UserId}")]
public async Task<List<AspNetUserLogins>> PostUserFavorite(int id_cd, string UserId)
{
User_FavoriteCd newEntry = new User_FavoriteCd();
newEntry.id_id = id_cd;
newEntry.datetime = DateTime.Now;
newEntry.UserId = UserId;
db.User_FavoriteCd.Add(newEntry);
db.SaveChanges();
List<AspNetUserLogins> UserProvider = await db.AspNetUserLogins
.Where(up => up.UserId == UserId)
.ToListAsync();
return UserProvider;
}

If you do not need a return value you can do:
[Route("api/User/PostUserFavorite/{id_cd}/{UserId}")]
public async Task PostUserFavorite(int id_cd, string UserId)
{
User_FavoriteCd newEntry = new User_FavoriteCd();
newEntry.id_id = id_cd;
newEntry.datetime = DateTime.Now;
newEntry.UserId = UserId;
db.User_FavoriteCd.Add(newEntry);
await db.SaveChangesAsync();
}

Related

Broken Favourites logic with c#.I want to save the story to favorites but It keeps giving me error that the page Save/storyId is not found

I want to save the story without ajax request,just with mvc logic.It keeps giving me error that the page Save/storyId is not found.Any help wiil be good.
I dont want to use api controllers,i want to take the stories id,take the data of that story and create a favstory object,inside the sql database.
Thats my Service Save method logic:
public int Save(int id,string title,string topic,string genredid,string psedonym,string favcon, string userId)
{
var story = this.data.Stories.Where(x => x.Id == id).FirstOrDefault();
var favbook = new FavouriteBook
{
FavTitle = story.Title,
FavTopic = story.Topic,
FavGenreId = story.GenreId,
FavUserAuthor = story.Pseudonym,
FavCon = story.StoryText
};
this.data.FavouriteBooks.Add(favbook);
this.data.SaveChanges();
return favbook.Id;
}
Thats the Controller Save method logic:
[HttpPost]
public IActionResult Send(int id,AddFavouriteModel postm)
{
var userId = this.User.FindFirst(ClaimTypes.NameIdentifier).Value;
this.favouris.Save(
id,
postm.FavTitle,
postm.FavTopic,
postm.FavGenre.Name,
postm.FavUserAuthor,
postm.FavCon,
userId
);
return RedirectToAction(nameof(Index));
}
Thats the link to the Save method,from which i try to get the stories id,
<a smooth="true" asp-controller="Favourites" asp-action="Save" asp-route-id="#sto.Id" class="btnfav"></a>
I don't know if its right,but i have never implented favourites logic with c#.

Moq Dapper - Multi-map error: splitOn column 'Id' was not found

I'm running into this problem, let me describe it with my code: https://github.com/UnoSD/Moq.Dapper/issues/20
I'm trying to mock a QueryAsync call using Moq.Dapper library and hitting the error:
Multi-map error: splitOn column 'Id' was not found
Here is the multi mapping query and code that works perfect:
var query = $#" SELECT * FROM [{nameof(Dashboard)}] dashboard
left join [{nameof(DashboardUser)}] dusers on dashboard.DashboardId = dusers.DashboardId
left join [Users] users on dusers.UserId = users.Id
WHERE dashboard.{nameof(accountId)} = #{nameof(accountId)} AND dashboard.{nameof(dashboardId)} = #{nameof(dashboardId)}";
Dashboard? dashboardEntity = null;
using (var connection = _context.CreateConnection())
{
var result = await connection.QueryAsync<Dashboard, DashboardUser, User, Dashboard?>(query,
(dashboard, dashboardUser, user) =>
{
if (dashboard == null) return null;
if (dashboardEntity == null)
{
dashboardEntity = dashboard;
dashboardEntity.Users = new List<DashboardUser>();
}
if (dashboardUser != null)
{
dashboardEntity.Users.Add(dashboardUser);
if (user != null) dashboardUser.User = user;
}
return dashboardEntity;
}, splitOn: $#"{nameof(Dashboard.DashboardId)},{nameof(Dashboard.DashboardId)},Id", param: new { accountId, dashboardId });
}
When Mocking the QueryAsync call I'm hitting the same problem as everyone else in the GitHub thread:
Func<Dashboard, DashboardUser, User, Dashboard?> funMap = (Dashboard, DashboardUser, User) => Mock.Of<Dashboard>();
public async Task Should_Get_Dashboard()
{
// Arrange
var connection = new Mock<DbConnection>();
IEnumerable<Dashboard> expected = GenFu.ListOf<Dashboard>(1);
connection.SetupDapperAsync(c => c.QueryAsync(It.IsAny<string>(), funMap, It.IsAny<object>(), It.IsAny<IDbTransaction>(),It.IsAny<bool>(),
"DashboardId,DashboardId,Id", // <-- SplitOn defined but error is *Multi-map error: splitOn column 'Id' was not found*
It.IsAny<int?>(), It.IsAny<CommandType?>()))
.ReturnsAsync(expected);
_context.Setup(x => x.CreateConnection()).Returns(connection.Object);
var dashboardRepository = new DashboardRepository(_context.Object, null, null);
CommonResult<Dashboard?> actual = new();
// Act
actual = await dashboardRepository.GetDashboard(3, 1);
}
Does anyone have a solution for this? It's the final thing for my Unit Test code coverage.
UPDATE:
I don't need to specify the mapping. See how the code TFirst, TSecond, TThird, TResult is faint/dimmed and I get the same problem even with it explicitly mapped:
I did try this method:
connection.SetupDapperAsync(c => c.QueryAsync<Dashboard>(It.IsAny<string>(), It.IsAny<Type[]>(), GetFunc, It.IsAny<object>(), It.IsAny<IDbTransaction>(), It.IsAny<bool>(), $#"{nameof(Dashboard.DashboardId)},{nameof(Dashboard.DashboardId)},Id", It.IsAny<int?>(), It.IsAny<CommandType?>()))
.ReturnsAsync(expected);
and got the error:
System.ArgumentException : When using the multi-mapping APIs ensure you set the splitOn param if you have keys other than Id (Parameter 'splitOn')
I checked the Dapper code and tried * for the SplitOn and that made no difference.
UPDATE 2:
The problem is the MultiMapAsync method and I can't mock it because its scope is private:
UPDATE 3:
I changed the Dapper method to Public to see if I could Mock it:
Func<Dashboard, DashboardUser, User, Dashboard?> funMap = (Dashboard, DashboardUser, User) => Mock.Of<Dashboard>();
private class DontMap { /* hiding constructor */ }
public async Task Should_Get_Dashboard()
{
// Arrange
var connection = new Mock<DbConnection>();
IEnumerable<Dashboard> expected = GenFu.ListOf<Dashboard>(1);
connection.SetupDapperAsync(c => c.MultiMapAsync<Dashboard, DashboardUser, User, DontMap, DontMap, DontMap, DontMap, Dashboard?>(new CommandDefinition(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<IDbTransaction>(), It.IsAny<int>(),It.IsAny<CommandType>(), CommandFlags.None, default), funMap, $#"{nameof(Dashboard.DashboardId)},{nameof(Dashboard.DashboardId)},Id")).ReturnsAsync(expected);
I get the error:
Specified method is not supported
Mocking Dapper extension methods provides no value. You end up just testing your own test code. I would do either an integration test, where you test the whole method on a small database, or pull the testable logic out of the Dapper call like this:
using (var connection = _context.CreateConnection())
{
var result = await connection.QueryAsync<Dashboard, DashboardUser, User, Dashboard?>(query,
(dashboard, dashboardUser, user) => CreateDashboardEntity(dashboardEntity, dashboard, dashboardUser, user),
splitOn: $#"{nameof(Dashboard.DashboardId)},{nameof(Dashboard.DashboardId)},Id", param: new { accountId, dashboardId });
}
public Dashboard? CreateDashboardEntity(Dashboard? dashboardEntity, Dashboard dashboard, DashboardUser dashboardUser, User user)
{
if (dashboard == null) return null;
if (dashboardEntity == null)
{
dashboardEntity = dashboard;
dashboardEntity.Users = new List<DashboardUser>();
}
if (dashboardUser != null)
{
dashboardEntity.Users.Add(dashboardUser);
if (user != null) dashboardUser.User = user;
}
return dashboardEntity;
}
Now you can unit-test CreateDashBoardEntity as much as you like, and there is no logic left in QueryAsync that haven't already been tested by the good Dapper developers.

Can't insert data in mongodb with insertOneAsync

I want to insert data into a mongodb database. It worked like a charm, but I have one collection where I can't insert in the database and I don't know why. I do literally the same.
This doesnt work here
public async Task AddVerifyAsync(VerifyModel verifyModel)
{
verifyModel.CreationDate = DateTime.Now;
await _context.Verifies().InsertOneAsync(verifyModel);
}
I checked it multiple times, ran the debug mode, checked the model etc, it is all absolutely correct.
This is the method which returns the collection:
public IMongoCollection<VerifyModel> Verifies()
{
return _database.GetCollection<VerifyModel>("VerifyModel");
}
These are the methods that are working:
public async Task AddUserAsync(UserModel user)
{
await _context.Users().InsertOneAsync(user);
}
The collection-returner is just the same as above but with the other types.
I even have tried to remove the DateTime thing. Also I set the _id before giving it to the AddVerifyAsync method. But I even have tried disabling that.
the _context is dependency injected in the constructor.
This is where both methods get used:
public async Task CreateUserAsync(UserModel user)
{
UserModel gotUser = await _userRepository.GetUserByEmailAsync(user.Email);
//check if exists
if (gotUser != null)
throw new DataException();
//set defaults and prevent, that the user tries to manipulate data
user.Active = false;
user.RegTimeStamp = DateTime.Now;
user.AdminLevel = 0;
user.OrganizationId = null;
user.OrganizationAdminLevel = null;
user.Password = BCrypt.Net.BCrypt.HashPassword(user.Password);
user.Balance = 0f;
user.ProfilePicture = "";
//Add the user to the repo
await _userRepository.AddUserAsync(user);
VerifyModel verifyModel = new VerifyModel();
verifyModel.UserId = user.Id;
verifyModel.Id = ObjectId.GenerateNewId().ToString();
//useractivation
verifyModel.Type = 0;
//insert the verifyuser in database
await _verifyRepository.AddVerifyAsync(verifyModel);
await _emailSenderService.SendMailAsync(user, EmailTemplate.RegisterMail, verifyModel.Id,
"Herzlich Willkommen bei flundr. Nur noch ein Schritt!", user.Email);
}
Here the Verifymodel doesnt get inserted in the db.

Updating Entity in EF6 gives primary key exception

When I try to update this object in EF6 I get an error stating more than 1 entity has this primary key. Looking at this DB I know this to be untrue(from what I can see).
I need to be able to update a second object based on one of the properties on the posted object. The code below produces the error. I have left in commented out pieces that I have tried to get this to work.
public async Task<ActionResult> Edit(PricingRule pricingRule)
{
if(ModelState.IsValid)
{
var currentUser = await serv.UserManager.FindByIdAsync(User.Identity.GetUserId());
var company = currentUser.Company;
//var entityRule = serv.PricingService.PricingRules.Get(pricingRule.PricingRuleId);
//If this is the first rule, set it to the company default
var rulesCount = company.PricingRules.Count;
if (rulesCount <= 1 || company.DefaultPricingRule == null)
pricingRule.DefaultPricingRule = true;
//Make sure no other rules are marked as default, and update the company with this rule as default
if (pricingRule.DefaultPricingRule)
{
if (company.DefaultPricingRule != null)
{
var oldRule = serv.PricingService.PricingRules.Get(company.DefaultPricingRule.PricingRuleId);
oldRule.DefaultPricingRule = false;
//serv.PricingService.PricingRules.Update(oldRule);
}
company.DefaultPricingRule = pricingRule;
serv.CoreService.Companies.Update(company);
}
serv.PricingService.PricingRules.Update(pricingRule);
await serv.SaveAllChangesAsync();
return RedirectToAction("Index");
}
return View(pricingRule);
}
Whether or not it is the best practice or how it should technically be done, this is how I solved my problem.
The edited object I was passing in, needed to be marked as modified first, before doing any other operations. I am assuming this is because the context could then grab it and all other operations regarding it would be done "within context". Other wise I think it was trying to add a new object if I tried to attach it to company.DefaultPricingRule.
public async Task<ActionResult> Edit(PricingRule pricingRule)
{
if(ModelState.IsValid)
{
serv.PricingService.PricingRules.Update(pricingRule);
var currentUser = await serv.UserManager.FindByIdAsync(User.Identity.GetUserId());
var company = currentUser.Company;
//If this is the first rule, set it to the company default
var rulesCount = company.PricingRules.Count;
if (rulesCount <= 1 || company.DefaultPricingRule == null)
pricingRule.DefaultPricingRule = true;
//Make sure no other rules are marked as default, and update the company with this rule as default
if (pricingRule.DefaultPricingRule)
{
if (company.DefaultPricingRule != null)
{
var oldRule = serv.PricingService.PricingRules.Get(company.DefaultPricingRule.PricingRuleId);
oldRule.DefaultPricingRule = false;
serv.PricingService.PricingRules.Update(oldRule);
}
company.DefaultPricingRule = pricingRule;
serv.CoreService.Companies.Update(company);
}
await serv.SaveAllChangesAsync();
return RedirectToAction("Index");
}
return View(pricingRule);
}
If Anyone has a comment on if this is best practice or if there is a better way to do it, I gladly take criticism.

Which one of these async calls is not like the other?

I suspect I have a deadlock issue, but it's an odd one that I can't rationalize. I have an API that needs to verify a few things in order to process the call. As part of the business logic, I might have to make more of those same calls as well. In this case, if a particular piece of data associated with an entity is not found, we attempt to use a backup (if one is configured), which requires checking other entities. Eventually, the code will hang.
Let's just dive into the code (comments highlight the calls in question).
API Controller:
public async Task<HttpResponseMessage> Get(int entityID, string content, bool? useBackUp = true)
{
//Some look-ups here, no issues at all
//This works, but it's this method that has an issue later in the process.
SystemEntity entityObj =
await BusinessLayer.GetSystemEntityAsync(SystemEntityID);
if (entityObj == null)
{
return new HttpResponseMessage
{
StatusCode = System.Net.HttpStatusCode.BadRequest,
Content = new StringContent("Entity is unavailable.")
};
}
string text = BusinessLayer.GetContentTextAsync(entityID
new List<string> {contentName}, useBackUp).Result.FirstOrDefault().Value;
if (text == null)
{
return new HttpResponseMessage {StatusCode = System.Net.HttpStatusCode.NoContent};
}
return new HttpResponseMessage
{
StatusCode = System.Net.HttpStatusCode.OK,
Content = new StringContent(text)
};
}
Business Layer:
public async Task<Dictionary<string, string>> GetContentTextAsync(int systemEntityID, List<string> contentNames, bool useBackUp)
{
Dictionary<string, string> records = new Dictionary<string, string>();
//We iterate for caching purposes
foreach (string name in contentNames)
{
string nameCopy = name;
string record = Cache.GetData(
string.Format("{0}_{1}_{2}", CONTENT, systemEntityID, name), () =>
DataLayer.GetCotnent(systemEntityID, nameCopy));
if (record == null && useBackUp)
{
List<int> entityIDs = new List<int> {systemEntityID};
int currentEntityID = systemEntityID;
//Here's that method again. This call seems to work.
SystemEntity currentEntity = await GetSystemEntityAsync(systemEntityID);
if (currentEntity != null && currentEntity.BackUpID.HasValue)
{
currentEntityID = (int) currentEntity.BackUpID;
}
while (!entityIDs.Contains(currentEntityID))
{
int id = currentEntityID;
record = Cache.GetData(
string.Format("{0}_{1}_{2}", CONTENT, systemEntityID, name), () =>
DataLayer.GetCotnent(id, nameCopy));
if (record != null) break;
entityIDs.Add(currentEntityID);
//This call seems to cause the deadlock
currentEntity = await GetSystemEntityAsync(currentEntityID);
if (currentEntity != null && currentEntity.BackUpID.HasValue)
{
currentEntityID = (int) currentEntity.UseBackupID;
}
}
}
if (record != null)
{
records.Add(name, record);
}
}
return records;
}
public async Task<SystemEntity> GetSystemEntityAsync(int systemEntityID)
{
SystemEntity systemEntity = await DataLayer.GetSystemEntity(
scc => scc.SystemEntityID == systemEntityID);
return systemEntity;
}
Data Layer:
public async Task<SystemEntity> GetSystemEntity(Expression<Func<SystemEntity, bool>> whereExpression)
{
using (EntityContext dbContext = createDbInstance())
{
//This is the last line that the debugger in VS 2013 brings me to. Stepping into this returns to whatever called the API method, waiting endlessly.
return await
dbContext.SystemEntity.Include(sc => sc.OtherEntity).Where(whereExpression).FirstOrDefaultAsync();
}
}
To recap: I call GetSystemEntityAsync three times. The first two times, it completes successfully. The third time, it hangs. If I comment out the first two calls so they don't run at all, the third one still hangs. If I remove the await and use just a normal FirstOrDefault in the return statement of the data layer method, then everything completes just fine.
Note: I have to keep the GetSystemEntityAsync method asynchronous. I cannot alter it to be synchronous.
What are the possible sources of the deadlock I'm encountering? I'm out of ideas on how to solve it.
Which one of these async calls is not like the other?
This one, I suspect:
string text = BusinessLayer.GetContentTextAsync(entityID
new List<string> {contentName}, useBackUp).Result.FirstOrDefault().Value;
Try changing it to this:
string text = (await BusinessLayer.GetContentTextAsync(entityID
new List<string> {contentName}, useBackUp)).FirstOrDefault().Value;
The possible source of the deadlock is described by Stephen Cleary in his "Don't Block on Async Code" blog post.

Categories