I'm trying to do the Entity Framework Code First Approach. I made my models then the DbContext and added it to the controller. I followed an online tutorial as I've never used C# before.
However the tables don't create until I add a call to the db in the controller.
public ActionResult Index()
{
db.posts.ToList();
return View();
}
The call however throws.
InvalidOperationException: The class 'SocialMediaMining.Models.SocialMedia.Facebook.posts' has no parameterless constructor.
posts class:
public class posts
{
public dynamic jsonObj { get; set; }
public posts(dynamic json)
{
jsonObj = json;
if (jsonObj != null)
{
id = jsonObj.id;
name = jsonObj.name;
if(jsonObj.feed !=null)
{
feed = new feed(jsonObj.feed);
}
}
}
public string id { get; set; }
public string name { get; set; }
public virtual feed feed { get; set; }
public int postsId { get; set; }
}
The controller:
public class FacebookController : Controller
{
//The dbcontext call
FacebookEntities db = new FacebookEntities();
public ActionResult Index()
{
// the error
db.posts.ToList();
return View();
}
// more code here
}
//DbContext
public class FacebookEntities : DbContext
{
public FacebookEntities() : base("SocialMediaDb")
{
}
public DbSet<posts> posts { get; set; }
//more code here
}
Any help is appreciated
The exception message is pretty straightforward - you need to specify a parameterless constructor for posts class, which should look like this:
public class posts
{
// add this constructor
public posts()
{
}
public dynamic jsonObj { get; set; }
public posts(dynamic json)
{
jsonObj = json;
if (jsonObj != null)
{
id = jsonObj.id;
name = jsonObj.name;
if(jsonObj.feed !=null)
{
feed = new feed(jsonObj.feed);
}
}
}
public string id { get; set; }
public string name { get; set; }
public virtual feed feed { get; set; }
public int postsId { get; set; }
}
Note that any entity class which want to be included in DbSet<T> type parameter must have parameterless constructor to enable binding with EF. Also it is recommended to use PascalCase for entity class names and property names, e.g. Posts.
Related
Problem:
I have an API endpoint which takes an IEmail input:
[HttpPost]
[Route("SendAsync")]
public async Task SendAsync(IEmail email)
{
await this._emailService.SendAsync(email);
}
The problem seems to be with the model binding of the Attachments property of this input. The model binder doesn't seem to be able to deserialise to my implementation. This is strange becuase the IEmail seems to be ok...
Exception:
System.NotSupportedException: The collection type 'IAttachmentCollection' on 'IEmail.Attachments' is not supported.
Setup:
See below for my contract and implementation for IEmail:
public interface IEmail
{
string To { get; set; }
string Subject { get; set; }
string Body { get; set; }
IAttachmentCollection Attachments { get; set; }
bool HasAttachments { get; }
}
public class EmailMessage : IEmail
{
public EmailMessage()
{
this.Attachments = new AttachmentCollection();
}
public string To { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
public IAttachmentCollection Attachments { get; set; }
public bool HasAttachments => this.Attachments != null && this.Attachments.Any(x => x.Content.Length > 0);
}
I have created a custom collection so that I can add custom validation into the Add() routine of the collection:
public interface IAttachmentCollection : ICollection<IAttachment>
{
}
public class AttachmentCollection : IAttachmentCollection
{
private ICollection<IAttachment> _attachments;
public AttachmentCollection()
{
this._attachments = new HashSet<IAttachment>();
}
public void Add(IAttachment item)
{
// Do some custom validation on the item we are trying to add
this._attachments.Add(item);
}
// Other implemented methods for ICollection<T>...
}
For complex types, Models are suppose to be concrete non-abstract classes with a default constructor by default in order for the action to be able to bind. It is also unable to determine what class to use for the interface property Attachments.
Reference Model Binding in ASP.NET Core
Create a model that mirrors the desired object graph
public class EmailModel {
public EmailModel() {
this.Attachments = new List<AttachmentModel>();
}
public string To { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
public List<AttachmentModel> Attachments { get; set; }
public bool HasAttachments => this.Attachments != null && this.Attachments.Any(x => x.Content.Length > 0);
}
public class AttachmentModel {
//...members
}
Explicitly use that for the action
[HttpPost]
[Route("SendAsync")]
public async Task<IActionResult> SendAsync([FromBody]EmailModel model) {
if(ModelState.IsValid) {
IEmain email = new EmailMessage();
//...code here to map model to the desired type
await this._emailService.SendAsync(email);
return Ok();
}
return BadRequest(ModelState);
}
Making sure to map the posted data to the desired type
When I'm trying to add a view for edit data reason, it gives me the error No parameterless constructor defined for this object
This is my controller:
public class MyNewPageController : Controller
{
MyNewPageController c = new MyNewPageController();
public MyNewPageController()
{
}
public IActionResult Index(PedroJorge.DAL.ProductDAL pd)
{
List<CS_mostrarModel> pList = new List<CS_mostrarModel>(pd.Read());
return View("~/Views/MyNewPage/Index.cshtml", pList);
}
public ActionResult Edit(int ID)
{
List<CS_mostrarModel> pList = new List<CS_mostrarModel>();
//Get the student from studentList sample collection for demo purpose.
//You can get the student from the database in the real application
var std = pList.Where(s => s.ID == ID).FirstOrDefault();
return View(std);
}
[HttpPost]
public ActionResult Edit(Product std)
{
//write code to update student
return RedirectToAction("Index");
}
}
public class SampleContext : DbContext
{
public DbSet<Order> Orders { get; set; }
public SampleContext(DbContextOptions<SampleContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>().ToTable("Order");
}
}
Model:
public class CS_mostrarModel
{
public int ID { get; set; }
public string ProductName { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime Date { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public int Price { get; set; }
public int PersonsNumber { get; set; }
public string TourType { get; set; }
public int CarsNumber { get; set; }
}
I don't know what is wrong and I already tried everything that I saw in internet, so if someone know how to fix this please help!
Unless that is a typo, then chances are that having the controller creating an instance of itself in a local field is causing a stack overflow exception when the framework is trying to activate the controller.
Each instance will try to create another instance until you run out of space on the stack.
In previous versions, the exception thrown when creating a controller was swallowed by the framework and the standard unhelpful
No parameterless constructor defined for this object
message was thrown.
Remove
MyNewPageController c = new MyNewPageController();
from the controller and it should be able to be initialized when requested.
I'm using a .Net core backend with Entity Framework to retrieve objects to my angular2 frontend.
As long as I return flat objects from the backend I have not problems. But when I use an Linq Include I get an net::ERR_CONNECTION_RESET error. The error seems to occur as soon as the call returns from backend, but it never enters the result handler.
How can I return a complex object with lists inside the objects?
DocumentsController.cs:
[Produces("application/json")]
[Route("api/[controller]")]
public class DocumentsController : Controller
{
private readonly DatabaseContext _context;
public DocumentsController(DatabaseContext context)
{
_context = context;
}
// GET: api/Documents
[HttpGet]
public IEnumerable<Document> GetDocuments()
{
var documents = _context.Documents
.Include(x => x.Pages);
return documents;
}
}
Document.cs:
public class Document : IEntity
{
public int Id { get; set; }
public string Title { get; set; }
public string AlternativeTitle { get; set; }
public ICollection<Page> Pages { get; set; }
}
Page.cs:
public class Page : IEntity
{
public Document Document { get; set; }
public int DocumentId { get; set; }
public int Id { get; set; }
public string OriginalText { get; set; }
public int Sorting { get; set; }
}
documents.components.ts:
import { Component, Inject } from '#angular/core';
import { Http } from '#angular/http';
#Component({
selector: 'documents',
templateUrl: './documents.component.html'
})
export class DocumentsComponent {
public documents: Document[];
constructor(http: Http, #Inject('BASE_URL') baseUrl: string) {
http.get(baseUrl + 'api/Documents').subscribe(result => {
this.documents = result.json() as Document[];
}, error => console.error(error));
}
}
interface Document {
title: string;
alternativeTitle: string;
pageCount: number;
pages: Array<Page>;
}
interface Page {
originalText: string;
sorting: number;
}
The connection reset error is due to your Action method throwing an unhandled exception, returning a 500 to the client. This happens because of the infinite loop Document => Page => Document when the serializer kicks in.
An easy way to solve this problem without breaking the relationship (you might need them even when using DTOs) is to change the default serialization process:
public IActionResult GetDocuments()
{
var documents = ...;
var options = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
return Json(documents, options);
}
With that said, you should always return either IActionResult or async Task<IActionResult> instead of the type directly (like IEnumerable<Document>).
Also, if you find yourself having to use the above code continuously, you might want to change the default options at the application level in Startup
After a while a thought struck me; it could be a problem with a never ending loop of Documents with Pages with nested Document with Pages and so on.
I created a DTO (data transfer object) that doesn't include the back references.
public class DocumentDto
{
public int Id { get; set; }
public string Title { get; set; }
public string AlternativeTitle { get; set; }
public ICollection<PageDto> Pages { get; set; }
public string OriginalLanguage { get; set; }
public string TranslationLanguage { get; set; }
}
public class PageDto
{
public int Id { get; set; }
public string OriginalText { get; set; }
public int Sorting { get; set; }
public string Translation { get; set; }
}
Worked like a charm.
I'm trying myself at a model that uses a generic type that I constrained with a base class.
I get the following error when calling my view:
The model item passed into the dictionary is of type 'MVCTest.Models.TestModel`1[MVCTest.Models.SpecialColumn]', but this dictionary requires a model item of type 'MVCTest.Models.TestModel`1[MVCTest.Models.ColumnBase]'.
Here is an example code to demonstrate the issue:
public class ColumnBase
{
public decimal Id { get; set; }
public string Text { get; set; }
public bool Enabled { get; set; }
public ColumnBase()
{
Enabled = true;
}
public string GetFormattedText(string symbol)
{
return string.Format(Text, symbol);
}
}
public class SpecialColumn : ColumnBase
{
public string Baz { get; set; }
}
public class TestModel<TColumn>
where TColumn : ColumnBase
{
Dictionary<string, TColumn> Columns { get; set; }
}
The Controller:
public ActionResult Test ()
{
var testModel = new TestModel<SpecialColumn>();
return View("", testModel);
}
In the view I tried to use ColumnBase as this should be a shared view that just needs the properties provided by ColumnBase:
#model TestModel<ColumnBase>
What is the correct way to implement something like this?
I have a model like the following:
public class TestViewModel
{
string UpdateProperty { get; set; }
string IgnoreProperty { get; set; }
ComplexType ComplexProperty { get; set; }
}
where
public class ComplexType
{
long? Code { get; set; }
string Name { get; set; }
}
My controller action:
public Edit(int id, FormColleciton formCollection)
{
var model = service.GetModel(id);
TryUpdateModel(model);
//...
}
When calling the Edit action I have a formCollection parameter containing only a key/value for UpdateProperty.
After the call to TryUpdateModel UpdateProperty is set correctly, IgnoreProperty is left un-touched but ComplexProperty is set to null, even if it previously had a value.
Should TryUpdateModel() only modify properties that are a part of the request? If this is not the case what is the best way to work around this so ComplexProperty is only modified if it is included in the request?
After it was pointed out by Darin that the test case above didn't demonstrate the problem I have added a scenario where this problem really occurs:
public class TestViewModel
{
public List<SubModel> List { get; set; }
}
public class SubModel
{
public ComplexType ComplexTypeOne { get; set; }
public string StringOne { get; set; }
}
public class ComplexType
{
public long? Code { get; set; }
public string Name { get; set; }
}
Controller Action:
public ActionResult Index()
{
var model = new TestViewModel
{
List = new List<SubModel> {
new SubModel{
ComplexTypeOne = new ComplexType{Code = 1, Name = "5"},
StringOne = "String One"
}
}
};
if (TryUpdateModel(model)) { }
return View(model);
}
Sending this request:
/Home/Index?List[0].StringOne=test
updates SubModel.StringOne property but sets ComplexTypeOne to null, even though it is not included in the request.
Is this expected behaviour (given this does not happen unless an enumerable of complex types is used)? How best to work around this?
There must be something wrong with your test case as I was unable to reproduce it. Here's what I tried:
Model (notice that I use public properties):
public class TestViewModel
{
public string UpdateProperty { get; set; }
public string IgnoreProperty { get; set; }
public ComplexType ComplexProperty { get; set; }
}
public class ComplexType
{
public long? Code { get; set; }
public string Name { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new TestViewModel
{
IgnoreProperty = "to be ignored",
UpdateProperty = "to be updated",
ComplexProperty = new ComplexType
{
Code = 1,
Name = "5"
}
};
if (TryUpdateModel(model))
{
}
return View();
}
}
Now I send the following request: /home/index?UpdateProperty=abc and inside the condition only the UpdateProperty is modified with the new value from the query string. All other properties, including the complex property, are left untouched.
Also notice that the FormCollection action parameter is useless.