try to send a viewmodel to view - asp.net

I have a asp mvc project :
Model:
public class TeamDto
{
public int TenantId { get; set; }
public string Name { get; set; }
public List<UserListDto> Users { get; set; }
}
public class AddTeamViewModel
{
public TeamDto Team { get; set; }
public List<UserListDto> AllUsers { get; set; }
}
Controller:
public async Task<IActionResult> AddOrEditTeam(int id = 0)
{
var users = await _userAppService.GetAllUsers();
var view = new AddTeamViewModel { Team = new TeamDto(), AllUsers = users.ToList() };
if (id == 0) return View(view);
var team = await _teamAppService.GetTeamById(id);
return View(new AddTeamViewModel { AllUsers = users.ToList() , Team = team });
}
View:
<h4 class="m-portlet__head-caption">#(Model.Team.Id > 0 ? "Edit Team" : "Add Team")</h4>
I can not undrestand why I get this error:
An unhandled exception occurred while processing the request.
NullReferenceException: Object reference not set to an instance of an object.
AspNetCore.Areas_App_Views_Team_AddOrEditTeam.b__22_1()

It seems you are posting the value and then trying to send the viewmodel to a view. In this case, try redirecting to action instead of showing the View.
public async Task<IActionResult> AddOrEditTeam(int id = 0)
{
var users = await _userAppService.GetAllUsers();
var view = new AddTeamViewModel { Team = new TeamDto(), AllUsers = users.ToList() };
if (id == 0) return RedirectToAction("YourViewName",view);
var team = await _teamAppService.GetTeamById(id);
AddTeamViewModel teams = new AddTeamViewModel{
AllUsers = users.ToList(),
Team = team
};
return RedirectToAction("YourViewName", teams);
}
This will solve your object reference issue.

Related

Xamarin Essentials WebAuthenticator.AuthenticateAsync method doesn't return any result

I have added a WebAuthenticator.AuthenticateAsync method in my xamarin forms app with start up Url as "https://accounts.google.com/o/oauth2/auth"
and call back url as "myapp://"
I have also tried with call back url as "com.googleusercontent.apps.{clientId}:/oauth2redirect"
I am doing this to add google login in my xamarin forms app.
On this browser with available google accounts are been showing up and after successful completion of email authentication it returns to app but result is not returned from WebAuthenticator.AuthenticateAsync method.
On second time invocation of this method returns the first invocation result as cancelled by user and the browser opens again for second time email authentication.
But it works in ios.
I have added 3 classes
public class Auth0Client
{
private readonly OidcClient oidcClient;
public Auth0Client(Auth0ClientOptions options)
{
var discovery = new DiscoveryPolicy
{
ValidateEndpoints = false,
Authority = "https://accounts.google.com"
};
oidcClient = new OidcClient(new OidcClientOptions
{
Authority = $"https://accounts.google.com/o/oauth2/auth",
ClientId = options.ClientId,
Scope = options.Scope,
RedirectUri = options.RedirectUri,
Browser = options.Browser,
ProviderInformation = options.ProviderInformation,
Policy = new Policy
{
Discovery = discovery,
RequireAccessTokenHash = false
},
});
}
public IdentityModel.OidcClient.Browser.IBrowser Browser
{
get
{
return oidcClient.Options.Browser;
}
set
{
oidcClient.Options.Browser = value;
}
}
public async Task<LoginResult> LoginAsync()
{
return await oidcClient.LoginAsync();
}
}
public class Auth0ClientOptions
{
public Auth0ClientOptions()
{
}
public string Domain { get; set; }
public string ClientId { get; set; }
public string RedirectUri { get; set; }
public string Scope { get; set; }
public IBrowser Browser { get; set; }
public ProviderInformation ProviderInformation { get; set; }
}
public class WebBrowserAuthenticator : IBrowser
{
public async Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = default)
{
try
{
WebAuthenticatorResult result = await WebAuthenticator.AuthenticateAsync(
new Uri(options.StartUrl),new Uri(options.EndUrl));
var url = new RequestUrl(options.EndUrl)
.Create(new Parameters(result.Properties));
return new BrowserResult
{
Response = url,
ResultType = BrowserResultType.Success
};
}
catch (Exception ex)
{
return new BrowserResult
{
ResultType = BrowserResultType.UserCancel,
ErrorDescription = "Login canceled by the user."
};
}
}
}
In view model we are creating authoclient
private async void NavigateToGoogleLogin(object obj)
{
string clientId = null;
string redirectUri = null;
switch (Device.RuntimePlatform)
{
case Device.iOS:
clientId = AppConstants.GoogleiOSClientId;
redirectUri = AppConstants.GoogleiOSRedirectUrl;
break;
case Device.Android:
clientId = AppConstants.GoogleAndroidClientId;
redirectUri = AppConstants.GoogleAndroidRedirectUrl;
break;
}
var auth0client = new Auth0Client(new Auth0ClientOptions()
{
Domain = "accounts.google.com/o/oauth2/auth",
ClientId = clientId,
RedirectUri = redirectUri,
Scope = AppConstants.GoogleScope,
Browser = new WebBrowserAuthenticator(),
ProviderInformation = new ProviderInformation
{
IssuerName = "accounts.google.com",
AuthorizeEndpoint = AppConstants.GoogleAuthorizeUrl,
TokenEndpoint = AppConstants.GoogleAccessTokenUrl,
UserInfoEndpoint = AppConstants.GoogleUserInfoUrl,
KeySet = new JsonWebKeySet(),
},
});
var loginResult = await auth0client.LoginAsync();
}
We are using below constants in authoclient object creation
internal static string GoogleScope = "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile";
internal static string GoogleAuthorizeUrl = "https://accounts.google.com/o/oauth2/auth";
internal static string GoogleAccessTokenUrl = "https://www.googleapis.com/oauth2/v4/token";
internal static string GoogleUserInfoUrl = "https://www.googleapis.com/oauth2/v3/userinfo";
Xamarin forms version:5.0.0.2012
Xamarin essentials: 1.7.3
Thanks in advance

How do I prevent a duplicate entry for a Create/Edit Functionality in ASP.NET Core w/ EF?

I am trying to prevent a user from creating a form with a FirstName, LastName, and DOB that match an entry in the database and editing a form to match an existing entry. If you could also lead me to how I can show an error when this happens, that would be awesome.
My Model:
public class MRegForm
{
public int MRegFormId { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; } = string.Empty;
[Display(Name = "Last Name")]
public string LastName { get; set; } = string.Empty;
public DateTime DOB { get; set; }
[I tried Index attribute. It did not work for me. I was able to create new duplicate forms with no issues.
[Index(nameof(FirstName), nameof(LastName), nameof(DOB), IsUnique = true)]
public class MRegForm
{
I also tried this. Same thing.
protected override void OnModelCreating(ModelBuilder modelbuilder)
{
base.OnModelCreating(modelbuilder);
modelbuilder.Entity<MRegForm>()
.HasIndex(x => new { x.FirstName, x.LastName, x.DOB})
.IsUnique();
}
public DbSet<MRegForm> MRegForm { get; set; } = default!;
I think that there is maybe a way to prevent this in the OnPostAsync()
This is my create OnPostAsync():
public async Task<IActionResult> OnPostAsync()
{
MRegForm.CreatorId = UserManager.GetUserId(User);
var isAuthorized = await AuthorizationService.AuthorizeAsync(User, MRegForm, RegFormOperations.Create);
if (isAuthorized.Succeeded == false)
return Forbid();
Context.MRegForm.Add(MRegForm);
await Context.SaveChangesAsync();
return RedirectToPage("./Index");
}
This is my Edit OnPostAsync():
public async Task<IActionResult> OnPostAsync(int id)
{
var mRegForm = await Context.MRegForm.AsNoTracking().SingleOrDefaultAsync(m => m.MRegFormId == id);
if (mRegForm == null)
return NotFound();
MRegForm.CreatorId = mRegForm.CreatorId;
var isAuthorized = await AuthorizationService.AuthorizeAsync(User, MRegForm, RegFormOperations.Update);
if (isAuthorized.Succeeded == false)
return Forbid();
MRegForm.Status = mRegForm.Status; // the Status is the current Status - Do Not Reset
Context.Attach(MRegForm).State = EntityState.Modified;
try
{
await Context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MRegFormExists(MRegForm.MRegFormId))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool MRegFormExists(int id)
{
return (Context.MRegForm?.Any(e => e.MRegFormId == id)).GetValueOrDefault();
}
}
You can try to download the entity from the database if exists and make changes to it or creating new one if not exist.
Your clients can always make new MRegForm in the form, but you add or update in the back and. Bether option will be to pass the existing MRegForm to the form and the client see and change all props he need.
public async Task AddOrUpdate(MRegForm input)
{
var mRegForm = await Context.MRegForm
.FirstOrDefaltAsync(x => x.FirstName == input.FirstName && x.LastName == input.LastName && x.DOB == input.YourDate);
if(mRegForm != null)
{
//Make changes on mRegForm
mRegForm.SomeProp = input.SomeProp,
...
}
else
{
var newMRegForm = new MRegForm
{
//Set all props you need
}
await this.Context.AddAsync(newMRegForm );
}
await this.Context.SaveCangesAsync();
}

FindOneAndUpdateAsync Intermittently Returning Null

I am using MongoDB.Driver for .NET Core 3.1 and running into an issue were records are not being saved properly. They are intermittently coming back as null when calling FindOneAndUpdateAsync. I have a script that calls my below code 100 times. Out of those 100, 1-5 fail in the last method, SetChildFavoritesAsync. The results came back as null. Any suggestions on what I am doing wrong?
Example Calls
var id = 1;
var childName = "test";
var collectionEntry = await FindByIdOrCreateAsync(id);
collectionEntry.Children = new List<MyCollection.ChildClass>{
new MyCollection.ChildClass{
Name = childName,
Favorites = new List<MyCollection.ChildClass.Favorite>()
}
};
await FindByIdAndUpdateChildrenAsync(collectionEntry.Id, collectionEntry.Children);
var favorites = new List<MyCollection.ChildClass.Favorite>{
Name = "testFavorite"
};
var resultsOfSet = await SetChildFavoritesAsync(id, name, favorites)
//do stuff with resultsOfSet
Example Model
public class MyCollection
{
[MongoDB.Bson.Serialization.Attributes.BsonRepresentation(BsonType.ObjectId)]
[MongoDB.Bson.Serialization.Attributes.BsonId]
public string _Id { get; set; }
[MongoDB.Bson.Serialization.Attributes.BsonRequired]
public int Id { get; set; }
public List<ChildClass> Children { get; set; }
public class ChildClass
{
public string Name { get; set; }
public List<Favorite> Favorites { get; set; }
public class Favorite
{
public string Name { get; set; }
}
}
}
Example Methods
public async Task<MyCollection> FindByIdOrCreateAsync(int id)
{
var filter = Builders<MyCollection>.Filter.Eq(mc => mc.Id, id);
var update = Builders<MyCollection>.Update
.Set(mc => mc.Id, id)
.SetOnInsert(mc => mc.Children, new List<MyCollection.ChildClass>());
var options = new FindOneAndUpdateOptions<MyCollection> { ReturnDocument = ReturnDocument.After, IsUpsert = true };
return await _database.GetCollection<MyCollection>("MyCollectionName").FindOneAndUpdateAsync(filter, update, options);
}
public async Task<MyCollection> FindByIdAndUpdateChildrenAsync(int collectionId, List<MyCollection.ChildClass> children)
{
var filter = Builders<MyCollection>.Filter.Eq(mc => mc.Id, collectionId);
var update = Builders<MyCollection>.Update.Set(mc => mc.Children, children);
var options = new FindOneAndUpdateOptions<MyCollection> { ReturnDocument = ReturnDocument.After, IsUpsert = false };
return await _database.GetCollection<MyCollection>("MyCollectionName").FindOneAndUpdateAsync(filter, update, options);
}
public async Task<MyCollection> SetChildFavoritesAsync(int collectionId, string childName, List<MyCollection.ChildClass.Favorite> favorites)
{
var filter = Builders<MyCollection>.Filter.Eq(mc => mc.Id, collectionId);
filter &= Builders<MyCollection>.Filter.Eq("children.name", childName);
var update = Builders<MyCollection>.Update.Set("children.$.favorites", favorites);
var options = new FindOneAndUpdateOptions<MyCollection> { ReturnDocument = ReturnDocument.After };
var results = await _database.GetCollection<MyCollection>("MyCollectionName").FindOneAndUpdateAsync(filter, update, options);
if (results == null)
{
_log.Error($"Child Favorites didn't save: collectionId:{collectionId}, childName:{childName}");
}
else
{
_log.Debug($"Child Favorites: collectionId:{collectionId}, childName:{childName}, favorites:{Newtonsoft.Json.JsonConvert.SerializeObject(results)}");
}
return results;
}
Appears to be an issue with communication to the database. I added some retry logic, which solved the issue.

Unit tests fails after upgrading to .net core 2

Can someone maybe explain to me what this means and why am i getting it.
System.InvalidOperationException : When called from 'VisitLambda',
rewriting a node of type 'System.Linq.Expressions.ParameterExpression'
must return a non-null value of the same type. Alternatively, override
'VisitLambda' and change it to not visit children of this type.
I am getting it from my unit tests I am running the latest .net core 2 with EF core. all my tests were fine till i upgraded then i started getting the error.
The funny thing is, is that when i run the project the line were it fails in the the tests is ok.
This is my Test
[Fact]
public async Task GetUserProfileAsync_Where_Employee_Exist_Test()
{
// Given
var user = TestPrincipal.CreatePrincipalForEmployeeUser();
using (var factory = new TestContextFactory())
using (var context = factory.CreateInMemoryDatabase<ApplicationContext>())
{
this.SetDependencies(context);
var data = EmployeeValueHelper.GetEmployeeValues();
context.AddRange(data);
context.SaveChanges();
var sut = new ProfileService(new DbContextRepository<Data.Models.Employees.Employee>(context), this.userService, this.moqEmploymentStatusService.Object);
// When
// -> this method goes to a service and calls the below FindByIdAsync
var actual = await sut.GetProfileForUserAsync(user);
// Then
Assert.Equal(10, actual.EmployeeId);
}
}
public async Task<Employee> FindByIdAsync(long id)
{
var profile = await this.repository.Set
.Include(_ => _.Address) --> IT FAILS ON THIS LINE, IF I REMOVE THE INCLUDE THEN IT WORKS
.Include(_ => _.EmployeeImage)
.SingleOrDefaultAsync(_ => _.EmployeeId == id);
if (profile == null)
{
return null;
}
return profile;
}
UPDATE
Service Layer
public class ProfileService : GenericService<Employee>, IProfileService
{
private readonly DbContextRepository<Employee> repository;
private readonly IUserService userService;
public ProfileService(DbContextRepository<Employee> repository, IUserService userService)
: base(repository)
{
this.repository = repository;
this.userService = userService;
}
public Task<Employee> GetProfileForUserAsync(ClaimsPrincipal user)
{
var id = this.userService.GetEmployeeId(user);
return id.HasValue ? this.FindByIdAsync(id.Value) : null;
}
public async Task<Employee> FindByIdAsync(long id)
{
var profile = await this.repository.Set
.Include(_ => _.Address)
.Include(_ => _.EmployeeImage)
.SingleOrDefaultAsync(_ => _.EmployeeId == id);
if (profile == null)
{
return null;
}
return profile;
}
}
Employee Model
public class Employee : IValidatableObject
{
[Key]
[Column("pkEmpID")]
public long EmployeeId { get; set; }
[Column("fkCompanyID")]
public long CompanyId { get; set; }
public virtual Company Company { get; set; }
[Display(Name = "lblEmpNumber")]
public string EmpNumber { get; set; }
public virtual IList<Address> Address { get; set; } = new List<Address>();
// WITH SOME EXTRA STUFF NOT NEEDED FOR THIS
}
Repository
public class DbContextRepository<TEntity> : IGenericRepository<TEntity>, IDisposable
where TEntity : class
{
public DbContextRepository(ApplicationContext context)
{
this.Context = context;
this.Set = context.Set<TEntity>();
this.SetWithNoTracking = this.Set.AsNoTracking();
}
public ApplicationContext Context { get; }
public DbSet<TEntity> Set { get; }
public IQueryable<TEntity> SetWithNoTracking { get; }
// WITH SOME EXTRA STUFF NOT NEEDED FOR THIS
}
Hope this will shed more light

ASP .NET Web API SaveChangesAsync with Foreign Key Data

I have Customer and Address classes, something like this:
public class Customer
{
[PrimaryKey]
public int Id { get; set; }
public string CustomerName { get; set; }
public int ShippingAddressId { get; set; }
[ForeignKey("ShippingAddressId")]
public Address ShippingAddress { get; set; }
}
public class Address
{
[PrimaryKey]
public int Id { get; set; }
public string City { get; set; }
}
When I call a Web API to update the Customer, I pass an edited Customer object to this method. For example, I edit 2 properties: Customer.CustomerName and Customer.ShippingAddress.City
AuthenticationResult ar = await new AuthHelper().AcquireTokenSilentAsync();
if (ar.Token == null) return false;
using (var json = new StringContent(JsonConvert.SerializeObject(entity), UnicodeEncoding.UTF8, "application/json"))
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(Settings.ApiUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ar.Token);
using (HttpResponseMessage response = await client.PutAsync("api/" + type.ToString() + "/" + id, json))
{
response.EnsureSuccessStatusCode();
return await InsertOrReplaceResponse(type, response);
}
}
Here is the Web API:
[HttpPut("{id}")]
public async Task<IActionResult> PutCustomer([FromRoute] int id, [FromBody] Customer customer)
{
_context.Entry(customer).State = EntityState.Modified;
await _context.SaveChangesAsync();
return new StatusCodeResult(StatusCodes.Status204NoContent);
}
However, only Customer.CustomerName gets updated. The foreign key data (Customer.ShippingAddress.City) isn't updated in the Address table.
Any idea what I'm doing wrong?
Thanks!
Generally, I would expect the child Address entity to be update as well because you use foreign key association which also should be the default for one-to-one mappings (see here for more details). However, it seems that something is not setup right and you get independent association behavior where you have to manage child entity state yourself. Should be a simple fix in your case:
_context.Entry(customer).State = EntityState.Modified;
_context.Entry(customer.ShippingAddress).State = EntityState.Modified;

Resources