I keep getting this error when i run my MVC application. The app builds fine but throws this error on the runtime.
Here is the scenario.
[DisplayColumn("Name", "Name", false)]
public partial class ApplicationAction
{
public Guid ApplicationActionId { get; set; }
[Required, StringLength(150), Column("ActionName")]
public string Action { get; set; }
[Required, StringLength(150)]
public string Controller { get; set; }
[StringLength(150)]
public string Area { get; set; }
[StringLength(250)]
public string Description { get; set; }
//Navigation Properties
public virtual ICollection<ApplicationActionGroup> ApplicationActionGroups { get; set; }
public ApplicationAction()
{
ApplicationActionId = Guid.NewGuid();
}
}
public DbSet<ApplicationAction> ApplicationActions { get; set; }
public static ApplicationAction GetAction(string actionName, string controller, string area, IEnumerable<ApplicationAction> actions)
{
foreach (ApplicationAction a in actions)
{
if (a.Action.Equals(actionName, StringComparison.InvariantCultureIgnoreCase)
&& a.Controller.Equals(controller, StringComparison.InvariantCultureIgnoreCase)
&& (
(string.IsNullOrEmpty(a.Area) && string.IsNullOrEmpty(area)) ||
(!string.IsNullOrEmpty(a.Area) && a.Area.Equals(area, StringComparison.InvariantCultureIgnoreCase))
)
)
{
return a;
}
}
return null;
}
I get an error on GetAction method. It comes up as Invalid object name 'dbo.ApplicationAction'. The sql database, there is a table called ApplicationActions. Not sure whats causing this error.
are you sure that [DisplayColumn("Name", "Name", false)]
is a valid attribute for a class?
Related
I have connected my asp.net core project to MS SQL server and am trying to test my APIs after writing the controllers. Here are 2 of the data models that I am trying to use.
public partial class Content
{
public Guid CCuid { get; set; }
public Guid CPuid { get; set; }
public string? CContents { get; set; }
public decimal? CAmount { get; set; }
public string? CCheckNumber { get; set; }
public int? CQuantity { get; set; }
public string? CNotes { get; set; }
public DateTime CDateProcessed { get; set; }
public string? CUserName { get; set; }
public virtual Vompackage? CPu { get; set; }
}
public partial class Package
{
public Package()
{
Contents = new HashSet<Content>();
}
/// <summary>
/// Unique Package Identifier
/// </summary>
public Guid PPuid { get; set; }
public Guid PSuid { get; set; }
public string? PTrackingNumber { get; set; }
public string? PBolnumber { get; set; }
public string? PProductCode { get; set; }
public int? PQuantity { get; set; }
public int? PPallets { get; set; }
public int? PBoxes { get; set; }
public string? PNotes { get; set; }
public DateTime PDateEntered { get; set; }
public virtual Vomshipment? PSu { get; set; }
public virtual ICollection<Content> Contents { get; set; }
}
}
Now I am trying to add a content using postman. When I tried to add the following data,
{
"cAmount": 2332,
"cCheckNumber": "",
"cQuantity": 133,
"cNotes": "thank u ",
"cDateProcessed": "2020-12-02T13:40:47.207",
"cUserName": "ztinsley",
"CPu": null
}
It gives 400 response, and
"errors": {
"CPu": [
"The CPu field is required."
]
I used null! to make CPu nullable. And when I tested GET method to pull all the contents, it says "cPu": null for every data. Why is it having trouble adding a new data? I also tried to add options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true in AddControllers(), but the it gives me 500 response. Please help!
P.S.
I have attached my controller to see if I made any mistakes.
[Produces("application/json")]
[ApiController]
[Route("api/content")]
public class ContentController : Controller
{
private readonly IContentRepository _contentReporitory;
public ContentController(IContentRepository contentReporitory)
{
_contentReporitory = contentReporitory;
}
[HttpGet("{ccuid}")]
public async Task<ActionResult<Content>> GetContentById(Guid ccuid)
{
try
{
var result = await _contentReporitory.GetContentById(ccuid);
if (result == null)
{
return BadRequest();
}
return result;
}
catch (Exception)
{
return StatusCode(StatusCodes.Status500InternalServerError,
"Error retrieving data from the database");
}
}
[HttpPost("addcontent")]
public async Task<ActionResult<Content>> AddContent([FromBody]Content content)
{
try
{
if (content == null)
return BadRequest();
var newContent = await _contentReporitory.AddContent(content);
return CreatedAtAction(nameof(GetContentById),
new { id = newContent.CCuid }, newContent);
} catch (Exception)
{
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
}
My repository:
public class ContentRepository : IContentRepository
{
private readonly OperationsContext _operationsContext;
public ContentRepository(OperationsContext operationsContext)
{
_operationsContext = operationsContext;
}
public async Task<Content> AddContent(Content content)
{
var result = await _operationsContext.Contents.AddAsync(content);
await _operationsContext.SaveChangesAsync();
return result.Entity;
}
}
}
All project templates starting with .NET 6 (C# 10) enable the nullable context for the project. Projects created with earlier templates don't include this element, and these features are off unless you enable them in the project file or use pragmas. It means CPu is treated as a non-nullable property.
So you can simply send {} instead of null:
{
"cAmount": 2332,
"cCheckNumber": "",
"cQuantity": 133,
"cNotes": "thank u ",
"cDateProcessed": "2020-12-02T13:40:47.207",
"cUserName": "ztinsley",
"CPu": {}
}
Or just set
public virtual Package? CPu { get; set; }
Then you can send "CPu": null.
You can refer to this Docs to learn more.
Everything looks good but I don't understand why I still get an error like:
"System.InvalidCastException: The field of type DotnetCoreWebAPI.Enum+Blood must be a string, array or ICollection type."
I've left some meaningful snippets of code and the error I'm getting, below.
Model:
public class User
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
[MaxLength(100)]
public string Surname { get; set; }
[MaxLength(2)]
public Enum.Blood Blood { get; set; }
[MaxLength(50)]
public string Cellphone { get; set; }
[MaxLength(500)]
public string Adress { get; set; }
}
Enum:
public class Enum
{
public enum Blood
{
ARhDpositive,
ARhDnegative,
BRhDpositive,
BRhDnegative,
ORhDpositive,
ORhDnegative,
ABRhDpositive,
ABRhDnegative
}
}
Controller:
[HttpPost]
public ActionResult<UserReadDto> CreateUser(User userCreateDto)
{
var userModel = _mapper.Map<User>(userCreateDto);
_repository.CreateUser(userModel);
return Ok(userModel);
}
Service Configurations:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<UserContext>(opt => opt.UseSqlServer
(Configuration.GetConnectionString("DatabaseConnection")));
services.AddControllers().AddJsonOptions(opt =>
opt.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
services.AddScoped<IUserRepo, SqlUserRepo>();
}
Note:
I use Postman when I test api
I found out why problem occurs, I've wrote User instead of UserCreateDto in this line:
public ActionResult<UserReadDto> CreateUser(**UserCreateDto ** userCreateDto)
I am rather new to c# but I am building something to help me at work. We have a REST API which I am trying to tap into but I am having issues when it comes to deserializing the response.
My code:
namespace BSRestCleint
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
string key = "xxxxxxxx";
string endPoint = "https://api.broadsign.com:10889/rest";
private void bRun_Click(object sender, EventArgs e)
{
var client = new RestClient(endPoint);
var request = new RestRequest("/host/v14/by_id", Method.GET);
request.AddHeader("accept", "application/json");
request.AddHeader("Authorization", "Bearer " + key);
request.AddParameter("domain_id", "103947039");
request.AddParameter("ids", "195392183");
request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; };
request.RequestFormat = DataFormat.Json;
var response = client.Execute<Host>(request);
var host = JsonConvert.DeserializeObject<Host>(response.Content);
oResponse.Text = host.Name;
}
}
}
And this is my class:
namespace BSRestCleint
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Runtime.Serialization.Json;
using System.IO;
public partial class Host
{
[JsonProperty("config_profile_bag_id")]
public long ConfigProfileBagId { get; set; }
[JsonProperty("container_id")]
public long ContainerId { get; set; }
[JsonProperty("db_pickup_tm_utc")]
public string DbPickupTmUtc { get; set; }
[JsonProperty("discovery_status")]
public long DiscoveryStatus { get; set; }
[JsonProperty("display_unit_id")]
public long DisplayUnitId { get; set; }
[JsonProperty("domain_id")]
public long DomainId { get; set; }
[JsonProperty("geolocation")]
public string Geolocation { get; set; }
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("nscreens")]
public long Nscreens { get; set; }
[JsonProperty("public_key_fingerprint")]
public string PublicKeyFingerprint { get; set; }
[JsonProperty("remote_clear_db_tm_utc")]
public string RemoteClearDbTmUtc { get; set; }
[JsonProperty("remote_reboot_tm_utc")]
public string RemoteRebootTmUtc { get; set; }
[JsonProperty("volume")]
public long Volume { get; set; }
}
}
Finally the returning json:
{
"not_modified_since":"2018-06-05T22:22:18Z",
"host":[
{
"active":true,
"config_profile_bag_id":0,
"container_id":0,
"db_pickup_tm_utc":"2018-01-11T10:12:55",
"discovery_status":0,
"display_unit_id":0,
"domain_id":103947039,
"geolocation":"(0,0)",
"id":195392183,
"license_end_date":null,
"licensed":true,
"name":"Broadsign Services - Mathias - 16x64",
"nscreens":0,
"primary_mac_address":"00:0c:29:e0:e6:22",
"public_key_fingerprint":"REDACTED",
"remote_clear_db_tm_utc":"1970-01-01T00:00:00",
"remote_reboot_tm_utc":"2017-12-12T10:17:23",
"secondary_mac_address":"",
"volume":-1
}
]
}
I know that if I only process this part my code works:
{
"active":true,
"config_profile_bag_id":0,
"container_id":0,
"db_pickup_tm_utc":"2018-01-11T10:12:55",
"discovery_status":0,
"display_unit_id":0,
"domain_id":103947039,
"geolocation":"(0,0)",
"id":195392183,
"license_end_date":null,
"licensed":true,
"name":"Broadsign Services - Mathias - 16x64",
"nscreens":0,
"primary_mac_address":"00:0c:29:e0:e6:22",
"public_key_fingerprint":"REDACTED",
"remote_clear_db_tm_utc":"1970-01-01T00:00:00",
"remote_reboot_tm_utc":"2017-12-12T10:17:23",
"secondary_mac_address":"",
"volume":-1
}
I'd like to know how I could make my code work to handle the whole json so that I don't need to regex the returning value. Some of the responses would return multiple instances unlike there where there's only 1. It's probably a very simple solution but my grasp of the language is rather minute as I am new to it.
Any help would be appreciated.
Since, you are getting the host as array inside the another root object so you can define a new class as which is wrapping Host (array)
public class RootObject
{
public DateTime not_modified_since { get; set; }
public List<Host> Host { get; set; }
}
deserialization code need to be updated as
var root = JsonConvert.DeserializeObject<RootObject>(response.Content);
If you see, here deserializtion will happen for RootObject instead of Host.
Now, to get all hosts, use the below code:
var hosts = root.Host;
Or the first host from received hosts
var firstHost = root.Host.First();
You can extract it like this, without introducing new class:
var js = JObject.Parse(response.Content);
var hosts = JArray.Parse(obj["host"].ToString());
foreach (JObject host in hosts)
{
var h = JsonConvert.DeserializeObject<Host>(host)
//do what you need to do with host
}
You mentioned that there can be multiple hosts, so, you have to convert it to JArray, and loop through the array.
use this as your Host class instead (renamed to RootObject)
public partial class RootObject
{
[JsonProperty("not_modified_since")]
public DateTimeOffset NotModifiedSince { get; set; }
[JsonProperty("host")]
public List<Host> Host { get; set; }
}
public partial class Host
{
[JsonProperty("active")]
public bool Active { get; set; }
[JsonProperty("config_profile_bag_id")]
public long ConfigProfileBagId { get; set; }
[JsonProperty("container_id")]
public long ContainerId { get; set; }
[JsonProperty("db_pickup_tm_utc")]
public DateTimeOffset DbPickupTmUtc { get; set; }
[JsonProperty("discovery_status")]
public long DiscoveryStatus { get; set; }
[JsonProperty("display_unit_id")]
public long DisplayUnitId { get; set; }
[JsonProperty("domain_id")]
public long DomainId { get; set; }
[JsonProperty("geolocation")]
public string Geolocation { get; set; }
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("license_end_date")]
public object LicenseEndDate { get; set; }
[JsonProperty("licensed")]
public bool Licensed { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("nscreens")]
public long Nscreens { get; set; }
[JsonProperty("primary_mac_address")]
public string PrimaryMacAddress { get; set; }
[JsonProperty("public_key_fingerprint")]
public string PublicKeyFingerprint { get; set; }
[JsonProperty("remote_clear_db_tm_utc")]
public DateTimeOffset RemoteClearDbTmUtc { get; set; }
[JsonProperty("remote_reboot_tm_utc")]
public DateTimeOffset RemoteRebootTmUtc { get; set; }
[JsonProperty("secondary_mac_address")]
public string SecondaryMacAddress { get; set; }
[JsonProperty("volume")]
public long Volume { get; set; }
}
}
then deserialize
var rootObject = JsonConvert.DeserializeObject<RootObject>(response.Content);
var hosts = rootObject .Host;
I'm building REST API server in .NET core. I'm testing my code via Postman software. I have a problem with Include() method that enables me to attach navigation property data. I'm trying to get data in [HttpGet] action and objects that are being returned are wrong.
My code :
MODELS
Session model
public class Session
{
[Key]
public int IDSession { get; set; }
[Required]
public DateTime LogInTime { get; set; }
public DateTime LogOutTime { get; set; }
[Required]
public int IDUser { get; set; }
public User User { get; set; }
[Required]
public int IDMachine { get; set; }
public Machine Machine { get; set; }
}
User model
public class User
{
[Key]
public int IDUser { get; set; }
[Required]
public string Forename { get; set; }
[Required]
public string Name { get; set; }
public string AvatarPath { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public string Password { get; set; }
public User CreatedBy { get; set; }
public DateTime CreatedAt { get; set; }
public List<UserGroup> UsersGroups { get; set; }
public List<Alarm> ExecutedAlarms { get; set; }
public List<Alarm> ResetedAlarms { get; set; }
public List<AccessCard> Cards { get; set; }
public List<AccessCard> UserCardsAdded { get; set; }
public List<User> UsersAdded { get; set; }
public List<Session> Sessions { get; set; }
public List<EventsLog> Events { get; set; }
public List<Reference> References { get; set; }
public List<UserPermission> UsersPermissions { get; set; }
}
Session controller
[Produces("application/json")]
[Route("api/Sessions")]
public class SessionsController : Controller
{
private readonly DBContext _context;
#region CONSTRUCTOR
public SessionsController(DBContext context)
{
_context = context;
}
#endregion
#region HTTP GET
// GET: api/sessions
[HttpGet]
public async Task<IActionResult> GetSessions()
{
var sessions = await _context.Sessions.Include(s => s.User). ToListAsync();
if (sessions.Any())
{
return new ObjectResult(sessions);
}
else
{
return NotFound();
}
}
// GET: api/sessions/1
[HttpGet("{id}", Name = "GetSessionByID")]
public async Task<IActionResult> GetSessionByID(Int32 id)
{
var session = await _context.Sessions.Include(s => s.User).FirstOrDefaultAsync(s => s.IDSession == id);
if (session == null)
{
return NotFound();
}
else
{
return new ObjectResult(session);
}
}
#endregion
}
The idea is that User model contains List<Session> collection that he/she created. I want to be able to return users with its sessions
Of course Session model contains a single User because every session is related with a specific, single User.
Now, when I need to get all sessions objects in SessionController with GetSessions() or GetSessionsByID() I use POSTMAN [HttpGet] action like this : http://localhost:8080/api/sessions which returns me wrong data :
A session contains a user and in turn a single user is related with its sessions. It looks like it tries to return me Session object properly, includes User object but then it tries to include all sessions for that User. That's not what I want. It looks like some kind of a loop. Sessions shoud be returned with its User objects and that's it. How can I achieve that ? Am I doing some logical mistake in my models ?
Thanks !
I met also this issue recently. So, I've fixed it by adding this script in the Startup.cs file and ConfigureServices method :
services.AddMvc().AddJsonOptions(
options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
So, you suffix services.AddMvc() by this code who means that you have to make JSON.Net to ignore cycles finded to the nested object request. And of course having Newtonsoft.Json package installed to your project and referenced in each concerned file
For much clearer information, see this link at Related Data and Serialization section :
https://learn.microsoft.com/en-us/ef/core/querying/related-data
Hope this is helpfull for you
I've found many solutions for exporting a class to CSV but my problem is this:
The class I'm trying to export has a property that is an observablecollection. eg:
public class ShipmentForExport
{
public string WaybillNumber { get; set; }
public DateTime WaybillDate { get; set; }
public string CustomerName { get; set; }
public string CustomerCode { get; set; }
public string CollectingBranchName { get; set; }
public string CollectingBranchCode { get; set; }
public string RecipientName { get; set; }
public string RecipientPhoneNumber { get; set; }
public string RecipientCellphoneNumber { get; set; }
public string RecipientCompany { get; set; }
public string DestinationAddress1 { get; set; }
public string DestinationAddress2 { get; set; }
public string DestinationCity { get; set; }
public string DestinationSuburb { get; set; }
public string DestinationProvince { get; set; }
public string DestinationCountry { get; set; }
public string DestinationPostalCode { get; set; }
***public ObservableCollection<InHouseParcel> Parcels { get; set; }***
}
When I try export a list of shipments to csv it works but obviously the parcels do not export the way I want them to.
I have tried using Filehelpers Library and csvHelper as well.
Any help is greatly appreciated!!
Josh's answer is outdated nowadays. You can use a typeconverter like:
CsvHelper.TypeConversion.TypeConverterFactory.AddConverter<ObservableCollection<string>>(new CsvHelper.TypeConversion.StringListConverter());
using (var txt = new StreamReader(filename))
using (var reader = new CsvHelper.CsvReader(txt))
{ .... }
namespace CsvHelper.TypeConversion
{
public sealed class StringListConverter : DefaultTypeConverter
{
public override object ConvertFromString(TypeConverterOptions options, string text)
{
var oc = new ObservableCollection<string>();
if (text.IndexOf('|') >= 0)
{
var list = text.Split('|').ToList<string>();// base.ConvertFromString(options, text);
oc = new ObservableCollection<string>(list);
}
return oc;
}
public override string ConvertToString(TypeConverterOptions options, object value)
{
var l = value as IEnumerable<string>;
if ( l == null || l.Count() == 0)
{
return "";
}
return string.Join("|", l);
}
public override bool CanConvertFrom(Type type)
{
return type == typeof(string);
}
}
}
Using CsvHelper (a library I maintain)...
When writing, you'll have to write manually because writing of collection properties isn't supported.
foreach( var record in records )
{
csv.WriteField( record.WaybillNumber );
...
foreach( var parcel in record.Parcels )
{
csv.WriteField( parcel );
}
}
Reading is a little easier because you can add it in the mapping.
Map( m => m.Parcels ).ConvertUsing( row =>
{
var oc = new ObservableCollection<InHouseParcel>();
var parcel = row.GetField<InHouseParcel>( 17 );
oc.Add( parcel );
} );
You'll need to convert the field values into InHouseParcel and loop through the remainder of the fields in the row. I'll leave that task to you.