So, i have two projects, WebAPI and Client. The Client uses the database of the WebAPI project, and does not have it's own. Everything is working fine in one-to-one relationships and one-to-many relationships. However, i now need to figure out how to make it work with many-to-many relationships. I'll be posting my code, so, to better explain myself i will write with the real class names as you will be able to understand due to the code i will post further.
In my WebApi.Models i have two classes, PlanoManutencao and Ativo. This is a many-to-many relationship. Here are the classes:
public class PlanoManutencao
{
public PlanoManutencao()
{
Ativos = new List<Ativo>();
Operacoes = new List<Operacao>();
}
public int ID { get; set; }
public string Nome { get; set; }
public string Observacoes { get; set; }
public bool Permanente { get; set; }
public DateTime DataCriacao { get; set; }
public virtual ICollection<Ativo> Ativos { get; set; }
public virtual ICollection<Operacao> Operacoes { get; set; }
}
public class Ativo
{
public Ativo()
{
PlanosManutencao = new List<PlanoManutencao>();
}
public int ID { get; set; }
public string Nome { get; set; }
public string Descricao { get; set; }
public virtual ICollection<PlanoManutencao> PlanosManutencao { get; set; }
}
Now, in my WebAPI i'm using repositories, as follows:
public class PlanosManutencaoRepository : IPlanosManutencaoRepository
{
public ApplicationDbContext context;
public PlanosManutencaoRepository()
{
context = new ApplicationDbContext();
}
public PlanoManutencao Create(PlanoManutencao planoManutencao)
{
context.PlanosManutencao.Add(planoManutencao);
context.SaveChanges();
return planoManutencao;
}
public bool Delete(int id)
{
var planoManutencao = context.PlanosManutencao.Find(id);
if (planoManutencao != null)
{
context.PlanosManutencao.Remove(planoManutencao);
context.SaveChanges();
return true;
}
else return false;
}
public List<PlanoManutencao> GetData()
{
var planosManutencao = context.PlanosManutencao.ToList();
return planosManutencao;
}
public List<PlanoManutencao> GetData(DateTime data)
{
var planosManutencao = context.PlanosManutencao.Where(f => f.DataCriacao == data);
return planosManutencao.ToList();
}
public PlanoManutencao GetDataById(int id)
{
return context.PlanosManutencao.Find(id);
}
public bool Update(int id, PlanoManutencao planoManutencao)
{
var planoManutencaoAux = context.PlanosManutencao.Find(id);
if (planoManutencao != null)
{
planoManutencaoAux.DataCriacao = planoManutencao.DataCriacao;
context.SaveChanges();
return true;
}
else return false;
}
}
public class AtivosRepository : IAtivosRepository
{
public ApplicationDbContext context;
public AtivosRepository()
{
context = new ApplicationDbContext();
}
public Ativo Create(Ativo ativo)
{
context.Ativos.Add(ativo);
context.SaveChanges();
return ativo;
}
public bool Delete(int id)
{
var ativo = context.Ativos.Find(id);
if (ativo != null)
{
context.Ativos.Remove(ativo);
context.SaveChanges();
return true;
}
else return false;
}
public List<Ativo> GetData()
{
var ativos = context.Ativos.ToList();
return ativos;
}
public List<Ativo> GetData(string descricao)
{
var ativos = context.Ativos.Where(f => f.Descricao == descricao);
return ativos.ToList();
}
public Ativo GetDataById(int id)
{
return context.Ativos.Find(id);
}
public bool Update(int id, Ativo ativo)
{
var ativoAux = context.Ativos.Find(id);
if (ativo != null)
{
ativoAux.Nome = ativo.Nome;
ativoAux.Descricao = ativo.Descricao;
context.SaveChanges();
return true;
}
else return false;
}
}
Now, for the controllers, i have:
public class PlanosManutencaoController : ApiController
{
//private ApplicationDbContext db = new ApplicationDbContext();
private IPlanosManutencaoRepository repoPM = new PlanosManutencaoRepository();
// GET: api/PlanosManutencao
public IQueryable<PlanoManutencao> GetPlanoManutencaos()
{
return repoPM.GetData().AsQueryable();
}
// GET: api/PlanosManutencao/5
[ResponseType(typeof(PlanoManutencao))]
public IHttpActionResult GetPlanoManutencao(int id)
{
PlanoManutencao planoManutencao = repoPM.GetDataById(id);
if (planoManutencao == null)
{
return NotFound();
}
return Ok(planoManutencao);
}
// PUT: api/PlanosManutencao/5
[ResponseType(typeof(void))]
public IHttpActionResult PutPlanoManutencao(int id, PlanoManutencao planoManutencao)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != planoManutencao.ID)
{
return BadRequest();
}
bool isSucess = repoPM.Update(id, planoManutencao);
if (!PlanoManutencaoExists(id))
{
return NotFound();
}
return Ok();
}
// POST: api/PlanosManutencao
[ResponseType(typeof(PlanoManutencao))]
public IHttpActionResult PostPlanoManutencao(PlanoManutencao planoManutencao)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (repoPM.Create(planoManutencao) == null)
{
return StatusCode(HttpStatusCode.BadRequest);
}
return CreatedAtRoute("DefaultApi", new { id = planoManutencao.ID }, planoManutencao);
}
// DELETE: api/PlanosManutencao/5
[ResponseType(typeof(PlanoManutencao))]
public IHttpActionResult DeletePlanoManutencao(int id)
{
PlanoManutencao planoManutencao = repoPM.GetDataById(id);
if (planoManutencao == null)
{
return NotFound();
}
bool isSuccess = repoPM.Delete(id);
if (!isSuccess)
{
return StatusCode(HttpStatusCode.BadRequest);
}
return Ok();
}
private bool PlanoManutencaoExists(int id)
{
return repoPM.GetDataById(id) == null ? false : true;
}
}
public class AtivosController : ApiController
{
//private ApplicationDbContext db = new ApplicationDbContext();
private IAtivosRepository repoA = new AtivosRepository();
// GET: api/Ativos
public IQueryable<Ativo> GetAtivoes()
{
return repoA.GetData().AsQueryable();
}
// GET: api/Ativos/5
[ResponseType(typeof(Ativo))]
public IHttpActionResult GetAtivo(int id)
{
Ativo ativo = repoA.GetDataById(id);
if (ativo == null)
{
return NotFound();
}
return Ok(ativo);
}
// PUT: api/Ativos/5
[ResponseType(typeof(void))]
public IHttpActionResult PutAtivo(int id, Ativo ativo)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != ativo.ID)
{
return BadRequest();
}
bool isSucess = repoA.Update(id, ativo);
if (!AtivoExists(id))
{
return NotFound();
}
return Ok();
}
// POST: api/Ativos
[ResponseType(typeof(Ativo))]
public IHttpActionResult PostAtivo(Ativo ativo)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (repoA.Create(ativo) == null)
{
return StatusCode(HttpStatusCode.BadRequest);
}
return CreatedAtRoute("DefaultApi", new { id = ativo.ID }, ativo);
}
// DELETE: api/Ativos/5
[ResponseType(typeof(Ativo))]
public IHttpActionResult DeleteAtivo(int id)
{
Ativo ativo = repoA.GetDataById(id);
if (ativo == null)
{
return NotFound();
}
bool isSuccess = repoA.Delete(id);
if (!isSuccess)
{
return StatusCode(HttpStatusCode.BadRequest);
}
return Ok();
}
private bool AtivoExists(int id)
{
return repoA.GetDataById(id) == null ? false : true;
}
}
Now, as for the Client project, i'm using ViewModels,Controllers and Views.
ViewModels:
public class PlanoManutencaoViewModel
{
public PlanoManutencaoViewModel()
{
Ativos = new List<AtivoViewModel>();
Operacoes = new List<OperacaoViewModel>();
}
public int ID { get; set; }
[Display(Name = "Name")]
public string Nome { get; set; }
[Display(Name = "Observations")]
public string Observacoes { get; set; }
[Display(Name = "Permanent")]
public bool Permanente { get; set; }
[Display(Name = "Created")]
public DateTime DataCriacao { get; set; }
[Display(Name = "Assets")]
public virtual ICollection<AtivoViewModel> Ativos { get; set; }
[Display(Name = "Tasks")]
public virtual ICollection<OperacaoViewModel> Operacoes { get; set; }
}
public class AtivoViewModel
{
public AtivoViewModel()
{
PlanosManutencao = new List<PlanoManutencaoViewModel>();
}
public int ID { get; set; }
[Display(Name = "Name")]
public string Nome { get; set; }
[Display(Name = "Description")]
public string Descricao { get; set; }
public ICollection<PlanoManutencaoViewModel> PlanosManutencao { get; set; }
}
The controllers are as follows:
public class PlanosManutencaoController : Controller
{
// GET: PlanosManutencao
public async Task<ActionResult> Index()
{
var client = WebApiHttpClient.GetClient();
HttpResponseMessage response = await client.GetAsync("api/PlanosManutencao");
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
var planosManutencao =
JsonConvert.DeserializeObject<IEnumerable<PlanoManutencaoViewModel>>(content);
return View(planosManutencao);
}
else
{
return Content("Ocorreu um erro: " + response.StatusCode);
}
}
// GET: PlanosManutencao/Details/5
public async Task<ActionResult> Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var client = WebApiHttpClient.GetClient();
HttpResponseMessage response = await client.GetAsync("api/PlanosManutencao/" + id);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
var plano = JsonConvert.DeserializeObject<PlanoManutencaoViewModel>(content);
if (plano == null) return HttpNotFound();
return View(plano);
}
else
{
return Content("Ocorreu um erro: " + response.StatusCode);
}
}
// GET: PlanosManutencao/Create
public ActionResult Create()
{
PopulateDropDownListForAtivos();
return View();
}
// POST: PlanosManutencao/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(PlanoManutencaoViewModel planoManutencao)
{
try
{
PopulateDropDownListForAtivos(planoManutencao.Ativos);
var client = WebApiHttpClient.GetClient();
string planoManutencaoJSON = JsonConvert.SerializeObject(planoManutencao);
HttpContent content = new StringContent(planoManutencaoJSON, System.Text.Encoding.Unicode, "application/json");
var response = await client.PostAsync("api/PlanosManutencao", content);
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Index");
}
else
{
return Content("Ocorreu um erro: " + response.StatusCode);
}
}
catch
{
return Content("Ocorreu um erro.");
}
}
// GET: PlanosManutencao/Edit/5
public async Task<ActionResult> Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var client = WebApiHttpClient.GetClient();
HttpResponseMessage response = await client.GetAsync("api/PlanosManutencao/" + id);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
var planoManutencao = JsonConvert.DeserializeObject<PlanoManutencaoViewModel>(content);
if (planoManutencao == null) return HttpNotFound();
return View(planoManutencao);
}
return Content("Ocorreu um erro: " + response.StatusCode);
}
// POST: PlanosManutencao/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(PlanoManutencaoViewModel planoManutencao)
{
try
{
var client = WebApiHttpClient.GetClient();
string planoManutencaoJSON = JsonConvert.SerializeObject(planoManutencao);
HttpContent content = new StringContent(planoManutencaoJSON, System.Text.Encoding.Unicode, "application/json");
var response =
await client.PutAsync("api/PlanosManutencao/" + planoManutencao.ID, content);
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Index");
}
else
{
return Content("Ocorreu um erro: " + response.StatusCode);
}
}
catch
{
return Content("Ocorreu um erro.");
}
}
// GET: PlanosManutencao/Delete/5
public async Task<ActionResult> Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var client = WebApiHttpClient.GetClient();
HttpResponseMessage response = await client.GetAsync("api/PlanosManutencao/" + id);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
var planoManutencao = JsonConvert.DeserializeObject<PlanoManutencaoViewModel>(content);
if (planoManutencao == null) return HttpNotFound();
return View(planoManutencao);
}
return Content("Ocorreu um erro: " + response.StatusCode);
}
// POST: PlanosManutencao/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> DeleteConfirmed(int id)
{
try
{
var client = WebApiHttpClient.GetClient();
var response = await client.DeleteAsync("api/PlanosManutencao/" + id);
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Index");
}
else
{
return Content("Ocorreu um erro: " + response.StatusCode);
}
}
catch
{
return Content("Ocorreu um erro.");
}
}
private void PopulateDropDownListForAtivos(object ativos = null)
{
IEnumerable<AtivoViewModel> vm = null;
using (var client=WebApiHttpClient.GetClient())
{
HttpResponseMessage response = client.GetAsync("api/Ativos").Result;
if(response.IsSuccessStatusCode)
{
vm = response.Content.ReadAsAsync<IEnumerable<AtivoViewModel>>().Result;
}
}
var Ativos = vm.ToList().OrderBy(i => i.ID);
ViewBag.Ativos = new SelectList(Ativos, "ID", "Nome");
}
}
public class AtivosController : Controller
{
// GET: Ativos
public async Task<ActionResult> Index()
{
var client = WebApiHttpClient.GetClient();
HttpResponseMessage response = await client.GetAsync("api/Ativos");
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
var ativos =
JsonConvert.DeserializeObject<IEnumerable<AtivoViewModel>>(content);
return View(ativos);
}
else
{
return Content("Ocorreu um erro: " + response.StatusCode);
}
}
// GET: Ativos/Details/5
public async Task<ActionResult> Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var client = WebApiHttpClient.GetClient();
HttpResponseMessage response = await client.GetAsync("api/Ativos/" + id);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
var ativo = JsonConvert.DeserializeObject<AtivoViewModel>(content);
if (ativo == null) return HttpNotFound();
return View(ativo);
}
else
{
return Content("Ocorreu um erro: " + response.StatusCode);
}
}
// GET: Ativos/Create
public ActionResult Create()
{
return View();
}
// POST: Ativos/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(AtivoViewModel ativo)
{
try
{
var client = WebApiHttpClient.GetClient();
string ativoJSON = JsonConvert.SerializeObject(ativo);
HttpContent content = new StringContent(ativoJSON, System.Text.Encoding.Unicode, "application/json");
var response = await client.PostAsync("api/Ativos", content);
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Index");
}
else
{
return Content("Ocorreu um erro: " + response.StatusCode);
}
}
catch
{
return Content("Ocorreu um erro.");
}
}
// GET: Ativos/Edit/5
public async Task<ActionResult> Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var client = WebApiHttpClient.GetClient();
HttpResponseMessage response = await client.GetAsync("api/Ativos/" + id);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
var ativo = JsonConvert.DeserializeObject<AtivoViewModel>(content);
if (ativo == null) return HttpNotFound();
return View(ativo);
}
return Content("Ocorreu um erro: " + response.StatusCode);
}
// POST: Ativos/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(AtivoViewModel ativo)
{
try
{
var client = WebApiHttpClient.GetClient();
string ativoJSON = JsonConvert.SerializeObject(ativo);
HttpContent content = new StringContent(ativoJSON, System.Text.Encoding.Unicode, "application/json");
var response =
await client.PutAsync("api/Ativos/" + ativo.ID, content);
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Index");
}
else
{
return Content("Ocorreu um erro: " + response.StatusCode);
}
}
catch
{
return Content("Ocorreu um erro.");
}
}
// GET: Ativos/Delete/5
public async Task<ActionResult> Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var client = WebApiHttpClient.GetClient();
HttpResponseMessage response = await client.GetAsync("api/Ativos/" + id);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
var ativo = JsonConvert.DeserializeObject<AtivoViewModel>(content);
if (ativo == null) return HttpNotFound();
return View(ativo);
}
return Content("Ocorreu um erro: " + response.StatusCode);
}
// POST: Ativos/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> DeleteConfirmed(int id)
{
try
{
var client = WebApiHttpClient.GetClient();
var response = await client.DeleteAsync("api/Ativos/" + id);
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Index");
}
else
{
return Content("Ocorreu um erro: " + response.StatusCode);
}
}
catch
{
return Content("Ocorreu um erro.");
}
}
}
I'll post only the Create view of PlanoManutencao, which is:
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Nome, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Nome, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Nome, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Observacoes, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Observacoes, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Observacoes, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Permanente, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.Permanente)
#Html.ValidationMessageFor(model => model.Permanente, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="ativos">Assets</label>
<div class="col-md-10">
#Html.DropDownList("ativos",String.Empty)
#Html.ValidationMessageFor(model => model.Ativos)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.DataCriacao, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.DataCriacao, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.DataCriacao, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
EntityFramework creates the join table in the WebAPI DB just fine, but when i create one PlanoManutencao with one Ativo it creates the PlanoManutencao but does not add anything to the join table. I reckon it my be a mistake i have in the repositories or controllers, but i cannot solve it. I also followed lots of tutorials, none of which seem to solve my problem.
I'm sorry for the long explanation, and thank you in advance, only for reading such a text :)
Try doing this inside your PlanosManutencaoRepo:
public class PlanosManutencaoRepository : IPlanosManutencaoRepository
{
public PlanoManutencao Create(PlanoManutencao planoManutencao)
{
foreach(var a in planoManutencao.Ativos)
{
context.Ativos.Attach(a);
}
context.PlanosManutencao.Add(planoManutencao);
context.SaveChanges();
return planoManutencao;
}
}
Related
I run into another problem. I have a UserRole domain class which takes UserID and RoleID
public class User_Role
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
//nav prop
public User User { get; set; }
public Guid RoleId { get; set; }
//nav prop
public Role Role { get; set; }
}
Roles have 2 types Reader and Admin. I need them for authentication which I will implement later.
The problem is when I added a "Reader" I can add it again and again. I understand that I need to validate user_role. This is my User_role controller
[Route("api/[controller]")]
[ApiController]
public class UserRoleController : ControllerBase
{
public readonly IUserRepository _userRepository;
public readonly IRoleRepository _roleRepository;
public readonly IUserRoleRepository _userRoleRepository;
public UserRoleController(IUserRepository userRepository, IRoleRepository IRoleRepository,
IUserRoleRepository userRoleRepository)
{
_userRepository = userRepository;
_roleRepository = IRoleRepository;
_userRoleRepository = userRoleRepository;
}
[HttpGet]
public async Task<IActionResult> GetAllUserRoles()
{
var userRoleDomain = await _userRoleRepository.GetAllAsync();
return Ok(userRoleDomain);
}
[HttpGet]
[Route("{userRoleId:guid}")]
[ActionName("GetUserRoleById")]
public async Task<IActionResult> GetUserRoleById(Guid userRoleId)
{
var userRoleDomain = await _userRoleRepository.GetUserRoleByIdAsync(userRoleId);
if(userRoleDomain == null)
{
return NotFound();
}
var UserRoleDto = userRoleDomain.ConvertToDto();
return Ok(UserRoleDto);
}
[HttpPost]
public async Task<IActionResult> AddUserRole([FromBody]AddUserRoleRequest addUserRoleRequest)
{
if(!(await ValidateAddUserRoleAsync(addUserRoleRequest)))
{
return BadRequest(ModelState);
}
//CheckIfRoleExist
var userRoleDomain = new User_Role
{
RoleId = addUserRoleRequest.RoleId,
UserId = addUserRoleRequest.UserId
};
userRoleDomain = await _userRoleRepository.AddUserRoleAsync(userRoleDomain);
var userRoleDto = userRoleDomain.ConvertToDto();
return CreatedAtAction(nameof(GetUserRoleById), new { userRoleId = userRoleDto.Id}, userRoleDto);
}
[HttpDelete]
[Route("{userRoleId:guid}")]
public async Task<IActionResult> DeleteUserRole(Guid userRoleId)
{
var userRoleDomain = await _userRoleRepository.DeleteAsync(userRoleId);
if(userRoleDomain == null)
{
return NotFound();
}
var userRoleDto = userRoleDomain.ConvertToDto();
return Ok(userRoleDto);
}
[HttpPut]
[Route("{userRoleId:guid}")]
public async Task<IActionResult> UpdateUserRole([FromRoute]Guid userRoleId,
[FromBody]UpdateUserRoleRequest updateUserRoleRequest)
{
if(!(await ValidateUpdateUserRoleAsync(updateUserRoleRequest)))
{
return BadRequest(ModelState);
}
var userRoleDomain = new User_Role()
{
Id = userRoleId,
UserId = updateUserRoleRequest.UserId,
RoleId = updateUserRoleRequest.RoleId
};
userRoleDomain = await _userRoleRepository.UpddateAsync(userRoleId, userRoleDomain);
if(userRoleDomain == null)
{
return NotFound();
}
var userRoleDto = userRoleDomain.ConvertToDto();
return Ok(userRoleDto);
}
#region Validation methods
private async Task<bool> ValidateAddUserRoleAsync(AddUserRoleRequest addUserRoleRequest)
{
var user = await _userRepository.GetAsyncByIdWithRoles(addUserRoleRequest.UserId);
if (user == null)
{
ModelState.AddModelError(nameof(addUserRoleRequest.UserId),
$"{nameof(addUserRoleRequest.UserId)} UserId is invalid");
}
var role = await _roleRepository.GetAsync(addUserRoleRequest.RoleId);
if(role == null)
{
ModelState.AddModelError(nameof(addUserRoleRequest.RoleId),
$"{nameof(addUserRoleRequest.RoleId)} RoleId is invalid");
}
if(ModelState.ErrorCount > 0)
{
return false;
}
return true;
}
private async Task<bool> ValidateUpdateUserRoleAsync(UpdateUserRoleRequest updateUserRoleRequest)
{
var user = await _userRepository.GetUserByIdASync(updateUserRoleRequest.UserId);
if(user == null)
{
ModelState.AddModelError(nameof(updateUserRoleRequest.UserId),
$"{nameof(updateUserRoleRequest.UserId)} UserId is invalid");
}
var role = await _roleRepository.GetAsync(updateUserRoleRequest.RoleId);
if(role == null)
{
ModelState.AddModelError(nameof(updateUserRoleRequest.RoleId),
$"{nameof(updateUserRoleRequest.RoleId)} RoleId is invalid");
}
if(ModelState.ErrorCount > 0)
{
return false;
}
return true;
}
private async Task<bool> CheckIfRoleExist(AddUserRoleRequest addUserRoleRequest)
{
}
#endregion
}
I am thinking to validate this in my CheckIfRoleExist function. How do I check if this type of role is already added with a specific userId?
Adding call to repository
public async Task<bool> CheckIfAlreadyExistAsync(User_Role userRole)
{
var userRoleExist = await _webApiDbContext.User_Roles.AnyAsync(u => u.RoleId == userRole.RoleId && u.UserId == userRole.UserId);
if(userRoleExist != null)
{
return true;
}
return false;
}
Figured out something like this
private async Task<bool> CheckIfRoleExist(AddUserRoleRequest addUserRoleRequest)
{
var user = await _userRepository.GetAsyncByIdWithRoles(addUserRoleRequest.UserId);
if(user == null)
{
return false;
}
foreach(var roleAdded in user.UserRoles)
{
if(roleAdded.RoleId == addUserRoleRequest.RoleId)
{
ModelState.AddModelError(nameof(addUserRoleRequest.RoleId),
$"{nameof(addUserRoleRequest.RoleId)} user already have this role");
}
}
if (ModelState.ErrorCount > 0)
{
return false;
}
return true;
}
If you have cleaner answer dont be afraid to post it:)
I am working on Website in which front end is developed in Angular 7 . I am sending an array from angular in json format to c# asp.net core. I am getting data in below format
`First = {"model": [{
"_organization_Name": "erw",
"_designation": "dfs",
"_p_Start_Date": "2019-02-28T19:00:00Z",
"_p_End_Date": "2019-03-27T19:00:00Z"
},
{
"_organization_Name": "erwfg",
"_designation": "dfsfgfg",
"_p_Start_Date": "2019-02-28T19:00:00Z",
"_p_End_Date": "2019-03-27T19:00:00Z"
}
]
}`
My Method in asp.net core below
[HttpPost("[action]")]
public IActionResult SaveProfessional([FromBody]JObject prof)
{
var obj = new Candidate_Professional_Info_Table(_context);
obj.Identity_Number = 112131.ToString();
obj =
JsonConvert.DeserializeObject<Candidate_Educational_Info_Table>(prof);
var result = obj.SaveProfessional(prof);
return Ok(new { suces = "result" });
}
My code is not deserializing json object Any solution please as now I have spend one week in this problem. My c# model is given below
public int ID { get; set; }
public string Identity_Number { get; set; }
[Required]
[RegularExpression("^[a-zA-Z0-9]+$", ErrorMessage = "Organization Name Not Valid")]
public string Organization_Name { get; set; }
[Required]
[RegularExpression("^/d{1, 2}///d{1,2}///d{4}$")]
public DateTime? p_Start_Date { get; set; }
[RegularExpression("^/d{1, 2}///d{1,2}///d{4}$")]
public DateTime? p_End_Date { get; set; }
[Required]
[RegularExpression("^[a-zA-Z0-9]+$", ErrorMessage = "Designation Name Not Valid")]
public string Designation { get; set; }
public bool InProgress { get; set; }
[NotMapped]
public List<Candidate_Professional_Info_Table> listprof { get; set; }
[NotMapped]
private readonly RegConnString _Context;
public Candidate_Professional_Info_Table(RegConnString connString)
{
_Context = connString;
}
You have underscores before your properties thats why the JsonConvert cannot map properly.
You can use [JsonProperty("")] attributes to map to the correct property
your properties would look like then
[Required]
[RegularExpression("^[a-zA-Z0-9]+$", ErrorMessage = "Organization Name Not Valid")]
[JsonProperty("_organization_Name")]
public string Organization_Name { get; set; }
[Required]
[RegularExpression("^/d{1, 2}///d{1,2}///d{4}$")]
[JsonProperty("_p_Start_Date")]
public DateTime? p_Start_Date { get; set; }
[RegularExpression("^/d{1, 2}///d{1,2}///d{4}$")]
[JsonProperty("_p_End_Date")]
public DateTime? p_End_Date { get; set; }
[Required]
[RegularExpression("^[a-zA-Z0-9]+$", ErrorMessage = "Designation Name Not Valid")]
[JsonProperty("_designation")]
public string Designation { get; set; }
To handle for the rest. You have a root object called model. But all we want is the List<Candidate_Educational_Info_Table>
public IActionResult SaveProfessional([FromBody]JObject prof)
{
//select the model itself. Also do some nullchecking to prevent errors if empty
var fooModel = prof.First;
//select the content of the model(your actual array). Also do some nullchecking to prevent errors if empty
var fooObjectArray= fooModel.First;
var theDeserializedList = fooObjectArray.ToObject<List<Candidate_Educational_Info_Table>>();
foreach (var item in theDeserializedList)
{
//handle the rest of what you want to do.
//As i see you inject the context into the objects on create but this will not be possible if you use the deserialze.
//Its better to pass the context on the method SaveProfessional
}
return Ok(new { suces = "result" });
}
There are a variety of JSON serializers. The one i usually use is Newtonsoft Json
Movie m = JsonConvert.DeserializeObject<Movie>(json);
You can also use dynamic deserilaization, which can deserialise without a class definition. You can use System.Web.Script.Serialization to parse and get a dynamic object. It also requires System.Web.Extensions reference
JavaScriptSerializer js = new JavaScriptSerializer();
dynamic modelItems = js.Deserialize<dynamic>(json);
var cors = new EnableCorsAttribute("http://localhost:4200", "*", "*");
config.EnableCors(cors);
.Linq;
namespace MTBCTest.Controllers
{
[EnableCors(origins: "http://localhost:4200", headers: "*", methods: "*")]
public class UsersController : ApiController
{
private testingDbEntities db = new testingDbEntities();
// GET: api/Users
[HttpGet]
public IQueryable<User> GetUsers()
{
return db.Users;
}
// GET: api/Users/5
[ResponseType(typeof(User))]
[HttpGet]
public IHttpActionResult GetUser(int id)
{
User user = db.Users.Find(id);
if (user == null)
{
return NotFound();
}
return Ok(user);
}
// PUT: api/Users/5
[ResponseType(typeof(void))]
[HttpPost]
public IHttpActionResult PutUser(User user)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
User ob = db.Users.Find(user.ID);
ob.FirstName = user.FirstName;
ob.LastName = user.LastName;
ob.Password = user.Password;
ob.EmailID = user.EmailID;
db.Entry(ob).State = EntityState.Modified;
db.SaveChanges();
return Ok();
}
// POST: api/Users
[HttpPost]
public IHttpActionResult PostUser(User user)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.InserUser(user.FirstName,user.LastName,user.EmailID, user.Password);
db.SaveChanges();
return Ok();
}
// DELETE: api/Users/5
[HttpGet]
public IHttpActionResult DeleteUser(int id)
{
User user = db.Users.Find(id);
if (user == null)
{
return NotFound();
}
db.Users.Remove(user);
db.SaveChanges();
return Ok();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool UserExists(int id)
{
return db.Users.Count(e => e.ID == id) > 0;
}
}
}
export class User {
public FirstName: string;
public LastName: string;
public EmailID: string;
public Password: string;
}
import { Injectable } from '#angular/core';
import { HttpClientModule, HttpClient, HttpHeaders } from '#angular/common/http';
import {User} from '../user';
import { Observable } from 'rxjs';
import { convertActionBinding } from
'#angular/compiler/src/compiler_util/expression_converter';
#Injectable({
providedIn: 'root'
})
export class UserServiceService {
// tslint:disable-next-line:variable-name
constructor(private _http: HttpClient) { }
public SaveUser(api: string , userData: User): Observable<any> {
// tslint:disable-next-line:no-trailing-whitespace
return this._http.post<any>(api, userData, {
headers : new HttpHeaders({
'Content-Type' : 'application/json'
})
});
}
public DeleteUser(api: string , id: number): Observable<any> {
return this._http.get<any>(api , {
// headers : new HttpHeaders({
// 'Content-Type' : 'application/x-www-form-urlencoded'
// }),
params: {
id: id.toString()
}
});
}
public editUserByID(api: string, userData: User): Observable<any> {
return this._http.post<any>(api, userData , {
// headers: new HttpHeaders({
// 'Content-Type' : 'application/json'
// })
});
}
public GetUsers(api: string): Observable<User[]> {
return this._http.get<User[]>(api);
}
public GetUsersByID(api: string , ID: number): Observable<User> {
return this._http.get<User>(api, {
// headers: new HttpHeaders({
// 'Content-Type': 'application/x-www-form-urlencoded'
// }),
params: {
ID: ID.toString()
}
});
}
}
import { Component, OnInit, OnDestroy } from '#angular/core';
import {UserServiceService} from 'src/Models/Services/user-service.service';
import { User } from 'src/Models/user';
import { Subscription } from 'rxjs';
#Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit, OnDestroy {
subscriptions: Subscription [] = [];
userData: User;
users: User[];
ifinserted: boolean;
isEdited: boolean;
// tslint:disable-next-line:variable-name
constructor(private _userService: UserServiceService) { }
ngOnInit() {
this.userData = new User();
this.ifinserted = false;
this.isEdited = false;
}
saveUser(data: User) {
console.log(data);
this._userService.SaveUser('http://localhost:58649/api/Users/PostUser' , data)
.subscribe();
this.ifinserted = true;
alert('Inserted');
}
getUser() {
this._userService.GetUsers('http://localhost:58649/api/Users/GetUsers')
.subscribe((data: User[]) => {
this.users = data;
});
}
editUser(i: number) {
this.subscriptions.push(
this._userService.GetUsersByID('http://localhost:58649/api/Users/GetUser' , i)
.subscribe((data: User) => {
this.userData = data;
this.isEdited = true;
}));
}
editUserByID(obj: User) {
this._userService.editUserByID('http://localhost:58649/api/Users/PutUser' , obj)
.subscribe();
this.isEdited = false;
alert('Edited');
}
deleteUser(i: number) {
console.log(i);
this._userService.DeleteUser('http://localhost:58649/api/Users/DeleteUser' , i)
.subscribe();
alert('Deleted');
}
ngOnDestroy() {
this.subscriptions.forEach(s => s.unsubscribe());
}
}
I use breakpoint debug it my ClientsId always come null and display on my payments index always is the first value of my Dropdownlist
Model:
public class Payments
{
[Key]
public int PaymentsId { get; set; }
public int ClientId { get; set; }
public virtual Client Client { get; set; }
}
ViewModel:
public class PaymentsViewModel
{
[Required(ErrorMessage = "Please select a client")]
[Display(Name = "Client")]
public int SelectedClient { get; set; }
public IEnumerable<SelectListItem> Client { get; set; }
}
GET CONTROLLER:
public ActionResult Create(Payments model)
{
var liste= new PaymentsViewModel
{
Clients = new SelectList(db.ClientList, "ClientId", "ClientName")
};
return View(liste);
}
POST CONTROLLER:
public ActionResult Create([Bind(Include = "....")] PaymentsViewModel model)
{
if (ModelState.IsValid)
{
model.PaymentsCreate();
return RedirectToAction("Index", "Payments");
}
return View(model);
}
CREATE VIEW:
#Html.DropDownListFor(m => m.SelectedClient, Model.Clients, "-Please select-", new { #class = "form-control" })
</div>
</div>
--------------------------------------------UPDATE---------------------------------------------------
EDIT CONTROLLER (GET):
public ActionResult Edit(int? id, PaymentsViewModel model)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Payments payments = db.PaymentsList.Find(id);
if (payments == null)
{
return HttpNotFound();
}
return View();
}
EDIT CONTROLLER (POST)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "PaymentsId,Paymentnumber,PaymentDate,Amount,Discount,Reference,Total")] Payments payments)
{
if (ModelState.IsValid)
{
db.Entry(payments).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(payments);
}
You should add a ClientsId initialization from model.SelectedClient at PaymentsCreate functions like: ClientsId = model.SelectedClient. And then you need to add SelectedClient string to properties enumeration at Create (post) method to Bind(Include.... attribute
I have controller
public class NewsController : Controller
{
private SchoolDbContext db = new SchoolDbContext();
//
// GET: /News/
public ActionResult Index()
{
return View(db.News.ToList());
}
//
// GET: /News/Details/5
public ActionResult Details(int id = 0)
{
News news = db.News.Find(id);
if (news == null)
{
return HttpNotFound();
}
return View(news);
}
//
// GET: /News/Create
public ActionResult Create()
{
return View();
}
//
// POST: /News/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(News news)
{
if (ModelState.IsValid)
{
var file = Request.Files[0];
if (file != null && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
string path2 = Path.GetRandomFileName();
fileName = path2 + fileName;
var path = Path.Combine(Server.MapPath("~/Uploads/"), fileName);
news.Image = fileName;
file.SaveAs(path);
}
db.News.Add(news);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(news);
}
//
// GET: /News/Edit/5
public ActionResult Edit(int id = 0)
{
News news = db.News.Find(id);
if (news == null)
{
return HttpNotFound();
}
return View(news);
}
//
// POST: /News/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(News news)
{
if (ModelState.IsValid)
{
db.Entry(news).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(news);
}
//
// GET: /News/Delete/5
public ActionResult Delete(int id = 0)
{
News news = db.News.Find(id);
if (news == null)
{
return HttpNotFound();
}
return View(news);
}
//
// POST: /News/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
News news = db.News.Find(id);
db.News.Remove(news);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
I have a Model
public class News
{
[Key]
public int newsID { get; set; }
[Required]
public string newsName { get; set; }
[Required]
public string newsDescription { get; set; }
public string Image { get; set; }
}
and a simple view
<div class="grid">
#foreach (var item in Model)
{
<div class="holder_content">
<section class="group1">
<h3>#Html.DisplayFor(modelItem => item.newsName)</h3>
<p class="desc">#Html.DisplayFor(modelItem => item.newsDescription)</p>
<a class="photo_hover3" href="#"><img src="~/Uploads/#Html.DisplayFor(modelItem => item.Image)" width="240" height="214" alt=""></a>
<div class="forbutton">
#Html.ActionLink("სრულად ", "Details", new { id = item.newsID }, new { #class = "button" })
</div>
#{ if (User.Identity.IsAuthenticated)
{
#Html.ActionLink("Edit ", "Edit", new { id = item.newsID })
#Html.ActionLink("Delete", "Delete", new { id = item.newsID })
}
}
</section>
}
I want to display this data in another page, where I have this code
#RenderPage("~/Views/News/Index.cshtml")
but web page goes on runtime error, with null pointer exception on foreach tag
have you any solution with this error? sorry for my english. Hope you understand
Please use the partial view rendering.
Note main thing you have to mention the namespace in the view page
Like : #model YourApplicationName.Models.exampleClassName
and then render the page as partial view.
#Html.Partial("partialViewName", new exampleClassName())
or other wise pass the model which you have denoted as namespace in the Partialview like below
#Html.Partial("partialViewName", #Modle.exampleClassName)
or
#Html.Partial("partialViewName", #Modle)
I followed the following tutorial to allow a user to login with Google and Facebook. How ever I have implemented It in a WEB API project as I am using a Node JS front end and Access by Mobile Applications. (http://www.asp.net/mvc/tutorials/mvc-5/create-an-aspnet-mvc-5-app-with-facebook-and-google-oauth2-and-openid-sign-on)
So what I would like to ask is how do I use the OAuth?
There is the default Account Controller with all the needed methods in.
1: How do I login to the WEB API From:
A: Web Site (Java Script)
B: Android Application?
From My understanding of it:
My Android application will have to call one of the Account Action Methods with the appropriate data.
Which Action Method?
What Data do I need to send it?
Here is the Account Controller: (Sorry Its quite long):
[Authorize]
[RoutePrefix("api/Account")]
public class AccountController : ApiController
{
private const string LocalLoginProvider = "Local";
public AccountController()
: this(Startup.UserManagerFactory(), Startup.OAuthOptions.AccessTokenFormat)
{
}
public AccountController(UserManager<IdentityUser> userManager,
ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
{
UserManager = userManager;
AccessTokenFormat = accessTokenFormat;
}
public UserManager<IdentityUser> UserManager { get; private set; }
public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; private set; }
// GET api/Account/UserInfo
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("UserInfo")]
public UserInfoViewModel GetUserInfo()
{
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
return new UserInfoViewModel
{
UserName = User.Identity.GetUserName(),
HasRegistered = externalLogin == null,
LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null
};
}
// POST api/Account/Logout
[Route("Logout")]
public IHttpActionResult Logout()
{
Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
return Ok();
}
// GET api/Account/ManageInfo?returnUrl=%2F&generateState=true
[Route("ManageInfo")]
public async Task<ManageInfoViewModel> GetManageInfo(string returnUrl, bool generateState = false)
{
IdentityUser user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (user == null)
{
return null;
}
List<UserLoginInfoViewModel> logins = new List<UserLoginInfoViewModel>();
foreach (IdentityUserLogin linkedAccount in user.Logins)
{
logins.Add(new UserLoginInfoViewModel
{
LoginProvider = linkedAccount.LoginProvider,
ProviderKey = linkedAccount.ProviderKey
});
}
if (user.PasswordHash != null)
{
logins.Add(new UserLoginInfoViewModel
{
LoginProvider = LocalLoginProvider,
ProviderKey = user.UserName,
});
}
return new ManageInfoViewModel
{
LocalLoginProvider = LocalLoginProvider,
UserName = user.UserName,
Logins = logins,
ExternalLoginProviders = GetExternalLogins(returnUrl, generateState)
};
}
// POST api/Account/ChangePassword
[Route("ChangePassword")]
public async Task<IHttpActionResult> ChangePassword(ChangePasswordBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword,
model.NewPassword);
IHttpActionResult errorResult = GetErrorResult(result);
if (errorResult != null)
{
return errorResult;
}
return Ok();
}
// POST api/Account/SetPassword
[Route("SetPassword")]
public async Task<IHttpActionResult> SetPassword(SetPasswordBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);
IHttpActionResult errorResult = GetErrorResult(result);
if (errorResult != null)
{
return errorResult;
}
return Ok();
}
// POST api/Account/AddExternalLogin
[Route("AddExternalLogin")]
public async Task<IHttpActionResult> AddExternalLogin(AddExternalLoginBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
AuthenticationTicket ticket = AccessTokenFormat.Unprotect(model.ExternalAccessToken);
if (ticket == null || ticket.Identity == null || (ticket.Properties != null
&& ticket.Properties.ExpiresUtc.HasValue
&& ticket.Properties.ExpiresUtc.Value < DateTimeOffset.UtcNow))
{
return BadRequest("External login failure.");
}
ExternalLoginData externalData = ExternalLoginData.FromIdentity(ticket.Identity);
if (externalData == null)
{
return BadRequest("The external login is already associated with an account.");
}
IdentityResult result = await UserManager.AddLoginAsync(User.Identity.GetUserId(),
new UserLoginInfo(externalData.LoginProvider, externalData.ProviderKey));
IHttpActionResult errorResult = GetErrorResult(result);
if (errorResult != null)
{
return errorResult;
}
return Ok();
}
// POST api/Account/RemoveLogin
[Route("RemoveLogin")]
public async Task<IHttpActionResult> RemoveLogin(RemoveLoginBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result;
if (model.LoginProvider == LocalLoginProvider)
{
result = await UserManager.RemovePasswordAsync(User.Identity.GetUserId());
}
else
{
result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(),
new UserLoginInfo(model.LoginProvider, model.ProviderKey));
}
IHttpActionResult errorResult = GetErrorResult(result);
if (errorResult != null)
{
return errorResult;
}
return Ok();
}
// GET api/Account/ExternalLogin
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
[AllowAnonymous]
[Route("ExternalLogin", Name = "ExternalLogin")]
public async Task<IHttpActionResult> GetExternalLogin(string provider, string error = null)
{
if (error != null)
{
return Redirect(Url.Content("~/") + "#error=" + Uri.EscapeDataString(error));
}
if (!User.Identity.IsAuthenticated)
{
return new ChallengeResult(provider, this);
}
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
if (externalLogin == null)
{
return InternalServerError();
}
if (externalLogin.LoginProvider != provider)
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
return new ChallengeResult(provider, this);
}
IdentityUser user = await UserManager.FindAsync(new UserLoginInfo(externalLogin.LoginProvider,
externalLogin.ProviderKey));
bool hasRegistered = user != null;
if (hasRegistered)
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
ClaimsIdentity oAuthIdentity = await UserManager.CreateIdentityAsync(user,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookieIdentity = await UserManager.CreateIdentityAsync(user,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName);
Authentication.SignIn(properties, oAuthIdentity, cookieIdentity);
}
else
{
IEnumerable<Claim> claims = externalLogin.GetClaims();
ClaimsIdentity identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
Authentication.SignIn(identity);
}
return Ok();
}
// GET api/Account/ExternalLogins?returnUrl=%2F&generateState=true
[AllowAnonymous]
[Route("ExternalLogins")]
public IEnumerable<ExternalLoginViewModel> GetExternalLogins(string returnUrl, bool generateState = false)
{
IEnumerable<AuthenticationDescription> descriptions = Authentication.GetExternalAuthenticationTypes();
List<ExternalLoginViewModel> logins = new List<ExternalLoginViewModel>();
string state;
if (generateState)
{
const int strengthInBits = 256;
state = RandomOAuthStateGenerator.Generate(strengthInBits);
}
else
{
state = null;
}
foreach (AuthenticationDescription description in descriptions)
{
ExternalLoginViewModel login = new ExternalLoginViewModel
{
Name = description.Caption,
Url = Url.Route("ExternalLogin", new
{
provider = description.AuthenticationType,
response_type = "token",
client_id = Startup.PublicClientId,
redirect_uri = new Uri(Request.RequestUri, returnUrl).AbsoluteUri,
state = state
}),
State = state
};
logins.Add(login);
}
return logins;
}
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityUser user = new IdentityUser
{
UserName = model.UserName
};
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
IHttpActionResult errorResult = GetErrorResult(result);
if (errorResult != null)
{
return errorResult;
}
return Ok();
}
// POST api/Account/RegisterExternal
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
if (externalLogin == null)
{
return InternalServerError();
}
IdentityUser user = new IdentityUser
{
UserName = model.UserName
};
user.Logins.Add(new IdentityUserLogin
{
LoginProvider = externalLogin.LoginProvider,
ProviderKey = externalLogin.ProviderKey
});
IdentityResult result = await UserManager.CreateAsync(user);
IHttpActionResult errorResult = GetErrorResult(result);
if (errorResult != null)
{
return errorResult;
}
return Ok();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
UserManager.Dispose();
}
base.Dispose(disposing);
}
#region Helpers
private IAuthenticationManager Authentication
{
get { return Request.GetOwinContext().Authentication; }
}
private IHttpActionResult GetErrorResult(IdentityResult result)
{
if (result == null)
{
return InternalServerError();
}
if (!result.Succeeded)
{
if (result.Errors != null)
{
foreach (string error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
if (ModelState.IsValid)
{
// No ModelState errors are available to send, so just return an empty BadRequest.
return BadRequest();
}
return BadRequest(ModelState);
}
return null;
}
private class ExternalLoginData
{
public string LoginProvider { get; set; }
public string ProviderKey { get; set; }
public string UserName { get; set; }
public IList<Claim> GetClaims()
{
IList<Claim> claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, ProviderKey, null, LoginProvider));
if (UserName != null)
{
claims.Add(new Claim(ClaimTypes.Name, UserName, null, LoginProvider));
}
return claims;
}
public static ExternalLoginData FromIdentity(ClaimsIdentity identity)
{
if (identity == null)
{
return null;
}
Claim providerKeyClaim = identity.FindFirst(ClaimTypes.NameIdentifier);
if (providerKeyClaim == null || String.IsNullOrEmpty(providerKeyClaim.Issuer)
|| String.IsNullOrEmpty(providerKeyClaim.Value))
{
return null;
}
if (providerKeyClaim.Issuer == ClaimsIdentity.DefaultIssuer)
{
return null;
}
return new ExternalLoginData
{
LoginProvider = providerKeyClaim.Issuer,
ProviderKey = providerKeyClaim.Value,
UserName = identity.FindFirstValue(ClaimTypes.Name)
};
}
}
private static class RandomOAuthStateGenerator
{
private static RandomNumberGenerator _random = new RNGCryptoServiceProvider();
public static string Generate(int strengthInBits)
{
const int bitsPerByte = 8;
if (strengthInBits % bitsPerByte != 0)
{
throw new ArgumentException("strengthInBits must be evenly divisible by 8.", "strengthInBits");
}
int strengthInBytes = strengthInBits / bitsPerByte;
byte[] data = new byte[strengthInBytes];
_random.GetBytes(data);
return HttpServerUtility.UrlTokenEncode(data);
}
}
#endregion
}
}