Post {FromBody] from data model to execute a procedure - asp.net-web-api

I think I am on the right track here, but cannot quite get this over the line. Very new to WebAPI and c# my background in SQL I could really use a hint. So thank you very much for any feedback.
using VirtualAssistant.Models;
using VirtualAssistant.DataModel;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Web.Http.Description;
using System.Collections;
using System.Data.Entity.Core.Objects;
namespace VirtualAssistant.Controllers
{
public class CreateController : ApiController
{
// POST: ChatAi/CreateCase
[Route("CreateCase")]
public IHttpActionResult Post([FromBody]usp_CreateCase_Submit createCase_Submit )
{
usp_CreateCase_Result results = new CreateCaseEntities().usp_CreateCase(createCase_Submit).FirstOrDefault();
if (results.caseId == null)
{
return NotFound();
}
return Ok(results);
}
}
}
I am using these data Models to help support Post[FromBody]
namespace VirtualAssistant.DataModel
{
using System;
public partial class usp_CreateCase_Result
{
public string referenceId { get; set; }
public Nullable<int> caseId { get; set; }
public string slaPriorityName { get; set; }
public string helpDeskName { get; set; }
public string helpDeskPhoneNumber { get; set; }
public string providerCompanyName { get; set; }
public string providerDivisionName { get; set; }
public string serviceDetailName { get; set; }
public string serviceTypeName { get; set; }
public string serviceStreamName { get; set; }
public Nullable<System.DateTime> slaAllocateBy { get; set; }
public Nullable<System.DateTime> slaAttendBy { get; set; }
public Nullable<System.DateTime> slaCompleteBy { get; set; }
public string caseStage { get; set; }
public string statusCode { get; set; }
public string statusMessage { get; set; }
}
public partial class usp_CreateCase_Submit
{
public Nullable<int> personId { get; set; }
public Nullable<int> locationId { get; set; }
public Nullable<int> serviceDetailId { get; set; }
public Nullable<int> linkedCaseId { get; set; }
public string contactFullName { get; set; }
public string contactPhoneNumber { get; set; }
public string contactMobileNumber { get; set; }
public string contactEmailAddres { get; set; }
public string problemNote { get; set; }
public string costCode { get; set; }
public string authoriserEmailAddress { get; set; }
public bool isDraft { get; set; }
public bool isOnlineEmergencyConfirmed { get; set; }
}
}
The error I am left dealing with is:
Severity Code Description Project File Line Suppression State
Error CS7036 There is no argument given that corresponds to the
required formal parameter 'locationId' of
'CreateCaseEntities.usp_CreateCase(int?, int?, int?, int?, string,
string, string, string, string, string, string, bool?,
bool?)' LloydsVirtualAssistant C:\Users\Noel.Purdie2\OneDrive -
Mitie\MITIE Solutions Delivery
Team\ChatAI\LloydsVirtualAssistant\LloydsVirtualAssistant\Controllers\CreateController.cs 28 Active
I understand that using json I can only have a single imput in the from. The team I am working with insist on [FromBody] no use of URI. Every example i can find out there doesn't include using database objects.
I am using a data model to import the functions
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace VirtualAssistant.DataModel
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Core.Objects;
using System.Linq;
public partial class CreateCaseEntities : DbContext
{
public CreateCaseEntities()
: base("name=CreateCaseEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual ObjectResult<usp_CreateCase_Result> usp_CreateCase(Nullable<int> personId, Nullable<int> locationId, Nullable<int> serviceDetailId, Nullable<int> linkedCaseId, string contactFullName, string contactPhoneNumber, string contactMobileNumber, string contactEmailAddress, string problemNote, string costCode, string authoriserEmailAddress, Nullable<bool> isDraft, Nullable<bool> isOnlineEmergencyConfirmed)
{
var personIdParameter = personId.HasValue ?
new ObjectParameter("PersonId", personId) :
new ObjectParameter("PersonId", typeof(int));
var locationIdParameter = locationId.HasValue ?
new ObjectParameter("LocationId", locationId) :
new ObjectParameter("LocationId", typeof(int));
var serviceDetailIdParameter = serviceDetailId.HasValue ?
new ObjectParameter("ServiceDetailId", serviceDetailId) :
new ObjectParameter("ServiceDetailId", typeof(int));
var linkedCaseIdParameter = linkedCaseId.HasValue ?
new ObjectParameter("LinkedCaseId", linkedCaseId) :
new ObjectParameter("LinkedCaseId", typeof(int));
var contactFullNameParameter = contactFullName != null ?
new ObjectParameter("ContactFullName", contactFullName) :
new ObjectParameter("ContactFullName", typeof(string));
var contactPhoneNumberParameter = contactPhoneNumber != null ?
new ObjectParameter("ContactPhoneNumber", contactPhoneNumber) :
new ObjectParameter("ContactPhoneNumber", typeof(string));
var contactMobileNumberParameter = contactMobileNumber != null ?
new ObjectParameter("ContactMobileNumber", contactMobileNumber) :
new ObjectParameter("ContactMobileNumber", typeof(string));
var contactEmailAddressParameter = contactEmailAddress != null ?
new ObjectParameter("ContactEmailAddress", contactEmailAddress) :
new ObjectParameter("ContactEmailAddress", typeof(string));
var problemNoteParameter = problemNote != null ?
new ObjectParameter("ProblemNote", problemNote) :
new ObjectParameter("ProblemNote", typeof(string));
var costCodeParameter = costCode != null ?
new ObjectParameter("CostCode", costCode) :
new ObjectParameter("CostCode", typeof(string));
var authoriserEmailAddressParameter = authoriserEmailAddress != null ?
new ObjectParameter("AuthoriserEmailAddress", authoriserEmailAddress) :
new ObjectParameter("AuthoriserEmailAddress", typeof(string));
var isDraftParameter = isDraft.HasValue ?
new ObjectParameter("IsDraft", isDraft) :
new ObjectParameter("IsDraft", typeof(bool));
var isOnlineEmergencyConfirmedParameter = isOnlineEmergencyConfirmed.HasValue ?
new ObjectParameter("IsOnlineEmergencyConfirmed", isOnlineEmergencyConfirmed) :
new ObjectParameter("IsOnlineEmergencyConfirmed", typeof(bool));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<usp_CreateCase_Result>("usp_CreateCase", personIdParameter, locationIdParameter, serviceDetailIdParameter, linkedCaseIdParameter, contactFullNameParameter, contactPhoneNumberParameter, contactMobileNumberParameter, contactEmailAddressParameter, problemNoteParameter, costCodeParameter, authoriserEmailAddressParameter, isDraftParameter, isOnlineEmergencyConfirmedParameter);
}
}
}

You are passing data to usp_CreateCase method in a wrong way, You need to update usp_CreateCase parameters to take one object of type usp_CreateCase_Submit
usp_CreateCase(usp_CreateCase_Submit createCase_Submit)
{
var personIdParameter = createCase_Submit.personId.HasValue ?
new ObjectParameter("PersonId", createCase_Submit.personId) :
new ObjectParameter("PersonId", typeof(int));
}

Related

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type because the type requires a JSON array

My api get json data like this
Office "دكتور نيوترشن"
officename "11111111"
address_user "سيتي مول"
profile_photo "profile_photo.png"
cover_photo "cover_photo.jpg"
agentarea "القطيف"
offertext "قريبا سوف توضح المصومات"
websiteurl "albatool-hdo"
and in xamarin android I am creating this class
public class Galeri
{
public Galeri()
{
}
public string Office { get; set; }
public string officename { get; set; }
public string address_user { get; set; }
public string profile_photo { get; set; }
public string cover_photo { get; set; }
public string agentarea { get; set; }
public string offertext { get; set; }
public string websiteurl { get; set; }
public string membertype { get; set; }
}
and also I am using this code to deserialized json
RunOnUiThread(() =>
{
itemGaleri = JsonConvert.DeserializeObject<List<Galeri>>(e.Result);
CustomListAdapter adapter = new CustomListAdapter(this, itemGaleri);
DaftarGaleri.Adapter = adapter;
progress.Visibility = ViewStates.Gone;
DaftarGaleri.ItemClick += DaftarGaleri_ItemClick;
}
);
but Iam getting an error
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type '' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
Next time when you have to deal with JSON and you want to quickly generate the C# models use services like https://app.quicktype.io. Now just give a logical names to your properties like Galeri instead of Welcome.
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
// using QuickType;
//
// var data = Welcome.FromJson(jsonString);
namespace QuickType
{
using System;
using System.Net;
using System.Collections.Generic;
using Newtonsoft.Json;
public partial class Welcome
{
[JsonProperty("Office")]
public string Office { get; set; }
[JsonProperty("officename")]
public string Officename { get; set; }
[JsonProperty("address_user")]
public string AddressUser { get; set; }
[JsonProperty("profile_photo")]
public string ProfilePhoto { get; set; }
[JsonProperty("cover_photo")]
public string CoverPhoto { get; set; }
[JsonProperty("agentarea")]
public string Agentarea { get; set; }
[JsonProperty("offertext")]
public string Offertext { get; set; }
[JsonProperty("websiteurl")]
public string Websiteurl { get; set; }
[JsonProperty("membertype")]
public string Membertype { get; set; }
}
public partial class Welcome
{
public static Welcome[] FromJson(string json) => JsonConvert.DeserializeObject<Welcome[]>(json, Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this Welcome[] self) => JsonConvert.SerializeObject(self, Converter.Settings);
}
public class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
};
}
}

Convert collections of database entities to collections of view models

I am working on a .NET Core Web API
So far I used to return anonymous types in my controllers but now I want to start using the full power of swagger with auto documentation of the return types.
Which lead me to start using view models.
But I am struggling with converting between the auto-generated database model classes
and the auto-generated swagger view model classes.
It works for a single instance (see GetPerson method in the controller below) but fails when I want to return lists.
So my questions:
How do I cast/convert collections/lists of objects between view models and database models
Is the code in the controller correct? Are there easier/shorter/better ways to do the conversion? (I read about using the implicit operator)
Error message I get:
Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Collections.Generic.List'. An explicit conversion exists (are you missing a cast?)
It gives me an InvalidCastException if I cast them explicitly like
List result = (List)_dbContext.Person....
there seems to be a problem with generics in the display of stackoverflow
Assume I used the generic lists with giving a type PersonView
My code looks like:
Database models
public partial class Person
{
public Person()
{
}
public int Id { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public int? MainAdressId { get; set; }
public virtual Adress MainAdress { get; set; }
}
public partial class Adress
{
public Adress()
{
Person = new HashSet();
}
public int Id { get; set; }
public string CityName { get; set; }
public int CityPostalCode { get; set; }
public string StreetName { get; set; }
public string HouseNumber { get; set; }
public string FloorNumber { get; set; }
public string DoorNumber { get; set; }
public virtual ICollection Person { get; set; }
}
View models
public class City
{
public string Name { get; set; }
public int PostalCode { get; set; }
}
public class Street
{
public string Name { get; set; }
public string HouseNumber { get; set; }
public string FloorNumber { get; set; }
public string DoorNumber { get; set; }
}
public class AdressView
{
public Street Street { get; set; }
public City City { get; set; }
}
public class PersonView
{
public string FirstName { get; set; }
public string Lastname { get; set; }
public AdressView Adress { get; set; }
}
The controller class which is working for a single instance but not for lists
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Swashbuckle.SwaggerGen.Annotations;
using PersonExample.ModelsPersonDB;
using PersonExample.ModelsViewPerson;
namespace PersonExample.Controllers
{
[Route("api/[controller]")]
public class PersonViewTestController : Controller
{
private readonly PersonDBContext _dbContext;
private readonly ILogger _logger;
public PersonViewTestController(PersonDBContext dbContext, ILogger logger)
{
_dbContext = dbContext;
_logger = logger;
_logger.LogDebug("{0} > new instance created", GetType().Name);
}
[HttpGet("{id:int}", Name = "GetPerson")]
[ProducesResponseType(typeof(PersonView), 200)]
[SwaggerOperation("GetPerson")]
public virtual IActionResult GetPerson([FromRoute]int id)
{
PersonView result = _dbContext.Person
.Include(p => p.MainAdress)
.Where(p => p.Id == id)
.Select(p => new PersonView()
{
FirstName = p.Firstname,
Lastname = p.Lastname,
Adress = (p.MainAdress == null) ? null :
new AdressView()
{
Street = new Street()
{
Name = p.MainAdress.StreetName,
HouseNumber = p.MainAdress.HouseNumber,
FloorNumber = p.MainAdress.FloorNumber,
DoorNumber = p.MainAdress.DoorNumber
},
City = new City()
{
Name = p.MainAdress.CityName,
PostalCode = p.MainAdress.CityPostalCode
}
}
}
)
.FirstOrDefault();
return new ObjectResult(result);
}
[HttpGet(Name = "GetPersonList")]
[ProducesResponseType(typeof(List), 200)]
[SwaggerOperation("GetPersonList")]
public virtual IActionResult GetPersonList()
{
List result = _dbContext.Person
.Include(p => p.MainAdress)
.Select(p => new PersonView()
{
FirstName = p.Firstname,
Lastname = p.Lastname,
Adress = (p.MainAdress == null) ? null :
new AdressView()
{
Street = new Street()
{
Name = p.MainAdress.StreetName,
HouseNumber = p.MainAdress.HouseNumber,
FloorNumber = p.MainAdress.FloorNumber,
DoorNumber = p.MainAdress.DoorNumber
},
City = new City()
{
Name = p.MainAdress.CityName,
PostalCode = p.MainAdress.CityPostalCode
}
}
}
);
return new ObjectResult(result);
}
}
}
you can use AutoMapper https://github.com/AutoMapper/AutoMapper/wiki/Getting-started
here some examples: Simple Automapper Example
example with EF core and ASP.NET WebApi: https://github.com/chsakell/aspnet5-angular2-typescript
I missed the .ToList() at the end of the query.
The full controller know looks like:
[HttpGet(Name = "GetPersonList")]
[ProducesResponseType(typeof(List), 200)]
[SwaggerOperation("GetPersonList")]
public virtual IActionResult GetPersonList()
{
List result = _dbContext.Person
.Include(p => p.MainAdress)
.Select(p => new PersonView()
{
FirstName = p.Firstname,
Lastname = p.Lastname,
Adress = (p.MainAdress == null) ? null :
new AdressView()
{
Street = new Street()
{
Name = p.MainAdress.StreetName,
HouseNumber = p.MainAdress.HouseNumber,
FloorNumber = p.MainAdress.FloorNumber,
DoorNumber = p.MainAdress.DoorNumber
},
City = new City()
{
Name = p.MainAdress.CityName,
PostalCode = p.MainAdress.CityPostalCode
}
}
}
).ToList(); //missed that line
return new ObjectResult(result);
}

Trying to Populate ViewModel List from Linq query MVC "List doesn't contain definiton for ..."error"

I am (trying to) build a multiple choice test application that will pass a list of multiple choice questions (select lists) from the controller to a view.
Then populate the view using a foreach loop, post the answers back to the controller, check them and increment the score for each correct answer and then update the db.
I am trying to populate the view model list using a Linq query (to keep my controller thin, I am doing this via a method in my Service layer).
Models
Questions (db first)
namespace AccessEsol.Models
{
using System;
using System.Collections.Generic;
public partial class Question
{
public Question()
{
this.ExamDets = new HashSet<ExamDet>();
}
public int QuID { get; set; }
public string Text1 { get; set; }
public string Text2 { get; set; }
public string CorrectAnswer { get; set; }
public string Foil1 { get; set; }
public string Foil2 { get; set; }
public string Foil3 { get; set; }
public string Level_ { get; set; }
public string GrammarPoint { get; set; }
public virtual ICollection<ExamDet> ExamDets { get; set; }
}
}
Exam
namespace AccessEsol.Models
{
using System;
using System.Collections.Generic;
public partial class Exam
{
public Exam()
{
this.Candidates = new HashSet<Candidate>();
this.ExamDets = new HashSet<ExamDet>();
}
public int ExamID { get; set; }
public string Name { get; set; }
public Nullable<System.DateTime> Date { get; set; }
public int AdminID { get; set; }
public string StartLevel { get; set; }
public virtual Administrator Administrator { get; set; }
public virtual ICollection<Candidate> Candidates { get; set; }
public virtual ICollection<ExamDet> ExamDets { get; set; }
}
}
There is also a model for Candidate that contains the CandID:
And the view model that uses these models:
namespace AccessEsol.Models
{
public class ExamQuestionsViewModel
{
public int QuID { get; set; }
public int CandID { get; set; }
public int ExamId { get; set; }
public string Text1 { get; set; }
public string Text2 { get; set; }
public string CorrectAnswer { get; set; }
public string Foil1 { get; set; }
public string Foil2 { get; set; }
public string Foil3 { get; set; }
public string Level { get; set; }
public string GrammarPoint { get; set; }
public virtual ICollection<ExamDet> ExamDets { get; set; }
}
}
This is the method that is to populate the view model:
public static List<ExamQuestionsViewModel> AddQuestions()
{
AccessEsolDataEntities db = new AccessEsolDataEntities();
string questionLevel = GetLevel();
int currentCand = GetCandID();
int currentExam = GetExamID();
//model = new DataAccess().Populate();
var qu = (from a in db.Questions
where a.Level_ == questionLevel
select a).ToList();
List<ExamQuestionsViewModel> exam = new List<ExamQuestionsViewModel>();
foreach (var IDs in exam)
{
currentCand = exam.CandID;
currentExam = exam.ExamId;
}
return (exam);
}
The error message I am getting is
'System.Collections.Generic.List<AccessEsol.Models.ExamQuestionsViewModel>'
does not contain a definition for 'ExamId' and no extension method
'ExamId' accepting a first argument of type
'System.Collections.Generic.List<AccessEsol.Models.ExamQuestionsViewModel>' could be found (are you missing a using directive or an assembly
reference?
What am I doing wrong here? All feedback much appreciated.
Please try this instead of your foreach:
foreach (var IDs in exam)
{
currentCand = IDs.CandID;
currentExam = IDs.ExamId;
}

Get data Self reference

I have a self reference model.
I want get data with linq.i want when status is ok return data.but if parent status is ok all of child return ok or pending or deleted.
how can i do this.
var model = _efComment.List(p => p.PostId == postId);
var list = model.ToList()
.Where(p => p.ComentStatus == ComentStatus.Ok)
.Where(x => x.Reply == null)
.ToList();using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using DomainModel.Classes;
namespace DomainModel
{
public class Comment : BaseFieldsTables
{
public string Content { get; set; }
public string WriterName { get; set; }
public string WriterEmail { get; set; }
public string WriterWebsite { get; set; }
public int PostId { get; set; }
[ForeignKey("PostId")]
public Post Post { get; set; }
public Comment Reply { set; get; }
public int? ReplyId { get; set; }
public ICollection<Comment> Children { get; set; }
public ComentStatus ComentStatus { get; set; }
}
}
namespace DomainModel
{
public enum ComentStatus
{
Ok = 1,
Pending = 2,
Deleted = 3
}
}

Object reference error in unit testing

i have a controller action
[HttpPost]
public ActionResult CreateFocus(FocusFormModel focus)
{
var errors = focusService.CanAddFocus(Mapper.Map<FocusFormModel, Focus>(focus)).ToList();
ModelState.AddModelErrors(errors);
if (ModelState.IsValid)
{
focusService.CreateFocus(Mapper.Map<FocusFormModel, Focus>(focus));
var createdfocus = focusService.GetFocus(focus.FocusName);
return RedirectToAction("Focus", new { id = createdfocus.FocusId });
}
return View("CreateFocus", focus);
}
This action is working fine but when i am writing unit test it is showing error
Object Reference Not set to an instance of an object
the uni test is
[Test]
public void Create_Focus()
{
// Arrange
GroupController controller = new GroupController(groupService);
// Act
FocusFormModel focus = new FocusFormModel();
focus.GroupId = 1;
focus.FocusName = "t";
focus.Description = "t";
Mapper.CreateMap<FocusFormModel, Focus>().ForAllMembers(opt => opt.Ignore());
Mapper.AssertConfigurationIsValid();
var result = (RedirectToRouteResult)controller.CreateFocus(focus);
Assert.AreEqual("Index", result.RouteValues["action"]);
}
My Model is described below
public class Focus
{
public int FocusId { get; set; }
[StringLength(50)]
public string FocusName { get; set; }
[StringLength(100)]
public string Description { get; set; }
public int GroupId { get; set; }
public virtual Group Group { get; set; }
public DateTime CreatedDate { get; set; }
public Focus()
{
CreatedDate = DateTime.Now;
}
}
and i am writing my view model as
public class FocusFormModel
{
public int FocusId { get; set; }
[Required(ErrorMessage = "*")]
[StringLength(50)]
public string FocusName { get; set; }
[Required(ErrorMessage = "*")]
[StringLength(100)]
public string Description { get; set; }
public int GroupId { get; set; }
public virtual Group Group { get; set; }
public DateTime CreatedDate { get; set; }
public FocusFormModel()
{
CreatedDate = DateTime.Now;
}
}
Can any one please help me
This line actually provides 2 chances to get null reference exception:
var errors = focusService.CanAddFocus(Mapper.Map<FocusFormModel, Focus>(focus)).ToList();
first of all focusService might be null
if focusService is not null then method call CanAddFocus(Mapper.Map<FocusFormModel, Focus>(focus)) might return null
That are just assumptions.
As Greg Smith said stack trace would be very helpful here.

Resources