Here is a problem.
We have a simple web api controller with one class in it
public class CheckApiController : ApiController
{
public class Test
{
public int Id { get; set; }
public string SomeString { get; set; }
/*public Test ComplexType
{
get
{
return new Test()
{
SomeString = "wtf"
};
}
}*/
}
public List<Test> Get()
{
return new List<Test>(){
new Test(){Id = 1,SomeString = "1st string"},
new Test(){Id=2,SomeString = "2nd string"}
};
}
public HttpResponseMessage Post(Test testclass)
{
//do something
var response = Request.CreateResponse(HttpStatusCode.Created);
return response;
}
}
When I check in fiddler Get and Post methods everything is OK. But when i uncomment the property ComplexType in Test and try again POST method will respond with huge 500 internal server error:
Insufficient stack to continue executing the program safely. This can happen from having too many functions on the call stack or function on the stack using too much stack space.
So its simple StackOverflow exception. So why this error happens with field that has no setter or how can i ignore it in binding?
Think about whats happening here. When you POST the object WebApi is building your Test class to build it it gets the ComplexType, which returns a new Test, which gets ComplexType, which returns a new Test and so on until you run out of stack.
Having any logic in you Model you send to/from your Api is generally not a great idea. Here is some info on DTOs, which explains why http://www.servicedesignpatterns.com/requestandresponsemanagement/datatransferobject
Id Recommend amending your Test class to look like:
public class Test
{
public int Id { get; set; }
public string SomeString { get; set; }
public Test ComplexType { get; set; }
}
And then assigning the 'SomeString' value afterwards.
Related
I have a vNext console application where one of my classes takes the OptionsModel<T> POCO configuration settings class.
I am unable to get the POCO settings class resolved and injected into my RabbitMqConnection class below.
Setting up the ServiceProvider is not the issue, it's the resolution of the settings class.
Note, this is a vNext console application (not an mvc6 app).
My second question is, and I understand constructor arguments should be kept minimal, but is it not best to pass the two strings as constructor arguments rather than an IOptions class as the former method is more descriptive of what the RabbitMqConnection class requires? If so, how is this best injected from the class that defined the mappings (Program.cs file in example below)
public class RabbitMqConnection
{
public string HostName { get; set; }
public string UserName { get; set; }
public RabbitMqConnection(IOptions<MessagingSettings> settings)
{
HostName = settings.Value.HostName;
UserName = settings.Value.UserName;
}
}
public class MessagingSettings
{
public string HostName { get; set; }
public string UserName { get; set; }
}
appsettings.json
{
"MessagingSettings":{
"HostName":"localhost",
"Username":"guest"
}
}
public void ConfigureServices(IServiceCollection services)
{
// tried registration a number of ways as below
services.Configure<MessagingSettings>(Configuration.GetSection("MessagingSettings"));
services.Configure<MessagingSettings>(Configuration);
// attempt 1 - get runtime error saying cant resolve IOptions<MessageSettings>
services.TryAdd(ServiceDescriptor.Singleton<RabbitMqConnection, RabbitMqConnection>());
// attempt 2 - same as above, when i breakpoint on messagingSettings, all the values in the object are null
services.TryAdd(ServiceDescriptor.Singleton<RabbitMqConnection>(factory =>
{
// instead of injecting the MessageSettings, pass through the string values (constructor omitted for clarity)
var messagingSettings = Configuration.Get<MessagingSettings>();
return new RabbitMqConnection(messagingSettings.HostName, messagingSettings.UserName);
}));
}
var conn = ServiceProvider.GetRequiredService<RabbitMqConnection>();
You need to call services.AddOptions()
I am getting this error "Self referencing loop detected" while serializing using 'Json.NET'
I have a Book model
public class Book
{
public Book()
{
BookPersonMap = new List<BookPersonMap>();
}
public int BookId { get; set; }
public virtual ICollection<BookPersonMap> BookPersonMap { get; private set; }
(And many other virtual Icollections)
}
And this is the BookPerson Mapping class:
public class BookPersonMap
{
public int BookId { get; set; }
public string PersonName { get; set; }
public int PersonTypeId { get; set; }
public virtual Book Book { get; set; } // Foreign keys
public virtual PersonType PersonType { get; set; }
}
When I try to Serialize the Book object it throws:
"Self referencing loop detected for property 'Book' with type 'System.Data.Entity.DynamicProxies.Book_57F0FA206568374DD5A4CFF53C3B41CFDDC52DBBBA18007A896 08A96E7A783F8'. Path 'BookPersonMap[0]'."
I have tried the things suggested in some of the similar posts
Example:
PreserveReferencesHandling = PreserveReferencesHandling.Objects in Serializer settings returned a string with length 3 million!
ReferenceLoopHandling = ReferenceLoopHandling.Ignore in Serializer settings :
"An exception of type 'System.OutOfMemoryException' occurred in Newtonsoft.Json.dll but was not handled in user code"
^ Same luck with "ReferenceLoopHandling.Serialize"
MaxDepth = 1 : Infinite loop again.
Putting [JsonIgnore] on the virtual properties is working but it is a tedious task (because of numerous FK references) and not efficent, since if I miss one property and it will throw exception.
What is missing from above Json settings for them be not working?
services.AddMvc().AddJsonOptions(opt => {
opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
I have found the best way to solve this type of error is to flatten your model using a view model.
Put a break point on your object before it is serialized and start drilling into the child properties. You will probably find that you can go on indefinitely.
This is what the serializer is choking on.
Create a Constructor for your controller and put on it this line of code :
db.Configuration.ProxyCreationEnabled = false;
//db is the instance of the context.
For asp.net mvc 5 use this
Add the code below to your Application_Start method inside globax.asax file or startup file.
protected void Application_Start()
{
..
GlobalConfiguration.Configuration.Formatters.JsonFormatter
.SerializerSettings
.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
}
Disable lazy loading and
ensure your controller does not return
Json(..obj)
rather it should return
Ok(..obj)
This is my first question, and I've agonised over what to write for a couple of days while Ive been trying to solve this problem.
I bought the Dependency Injection in .NET book by Mark Seeman, and have been trying to follow that and the examples on the Ninject website for creating an abstract factory class. The general idea is that I have a form contains a list of answers to questions. Answers can be of various types, so I am using a factory to create the relevant answer type.
I'm getting the error:
Error activating IAnswerValue
No matching bindings are available, and the type is not self-bindable.
Activation path:
1) Request for IAnswerValue
Suggestions:
1) Ensure that you have defined a binding for IAnswerValue.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
I initially tried with a parameter, but to simplify things for this example, Ive stripped it all out. None of the suggestions given in the error message seem to apply, the factory type is binding, as is the form service but the answervalue is apparently not.
This is the code from my NinjectWebCommon.cs
kernel.Bind<DomainModel.IAnswerValue>().To<DomainModel.AnswerValue>();
kernel.Bind<DomainModel.IAnswerValue>().To<DomainModel.StringAnswerValue>();
kernel.Bind<DomainModel.IAnswerValue>().To<DomainModel.DateTimeAnswerValue>();
kernel.Bind<IAnswerValueFactory>().ToFactory();
This is the answer class definition:
public class Answer
{
readonly IAnswerValueFactory answerValueFactory;
public int Id { get; set; }
public Question Question { get; set; }
public string Type { get; set; }
public Answer(IAnswerValueFactory answerValueFactory)
{
this.answerValueFactory = answerValueFactory;
}
public void GetAnswerValue()
{
var answer = this.answerValueFactory.GetAnswerValue();
}
public List<AnswerItem> PotentialAnswers { get; set; }
}
and the answer value:
public interface IAnswerValue
{
AnswerValue GetAnswerValue();
}
public class AnswerValue : IAnswerValue
{
readonly IAnswerValue answerValue;
public AnswerValue() { }
public AnswerValue(IAnswerValue answerValue)
{
this.answerValue = answerValue;
}
public AnswerValue GetAnswerValue()
{
// this will contain a switch statement to
// determine the type returned but I have
// omitted for this example
return new StringAnswerValue();
}
}
public class StringAnswerValue : AnswerValue
{
public string StringAnswer { get; set; }
}
and the factory:
public class AnswerValueFactory : IAnswerValueFactory
{
readonly IAnswerValue answerValue;
public AnswerValueFactory(IAnswerValue answerValue)
{
this.answerValue = answerValue;
}
public IAnswerValue GetAnswerValue()
{
return (IAnswerValue)this.answerValue.GetAnswerValue();
}
}
I feel like Ive exhausted my knowledge and Im just going around in circles trying the same thing over and over. There must be something quite simple Im missing, but I just cant see what it is.
I migrated an API method from a standard MVC action to the new asp.net Web-API beta and suddenly a read only property is no longer serialized (both returning JSON). Is this expected behaviour?
Edit: Added code sample
I have both Newtonsoft.Json 4.0.8 and System.Json 4.0 referenced through nuget packages
public IQueryable<Car> Gets()
{
return _carRepository.GetCars();
}
public class Car
{
public IEnumerable<Photo> Photos
{
get { return _photos; }
}
public string PreviewImageUrl // No longer serialized
{
get
{
var mainImage = Photos.FirstOrDefault(o => o.IsMainPreview) Photos.FirstOrDefault();
return mainImage != null ? mainImage.Url : (string.Empty);
}
}
}
}
The JsonMediaTypeFormatter that ships with the Beta uses a serializer that does not support read-only properties (since they would not round-trip correctly). We are planning on addressing this for the next realese.
In the mean-time you could use a custom JSON MediaTypeFormatter implementation that uses Json.NET (there's one available here) instead of the built-in formatter.
Update: Also check out Henrik's blog about hooking up a JSON.NET formatter: http://blogs.msdn.com/b/henrikn/archive/2012/02/18/using-json-net-with-asp-net-web-api.aspx
I don't know if this is an expected behavior or not. I would say that this is expected for input parameters (because you cannot set their values) but not for output parameters. So I would say this is a bug for an output parameter. And here's an example illustrating the issue:
Model:
public class Product
{
public Product()
{
Prop1 = "prop1 value";
Prop2 = "prop2 value";
Prop3 = "prop3 value";
}
public string Prop1 { get; set; }
[ReadOnly(true)]
public string Prop2 { get; set; }
public string Prop3 { get; protected set; }
}
Controller:
public class ProductsController : ApiController
{
public Product Get(int id)
{
return new Product();
}
}
Request:
api/products/5
Result:
{"Prop1":"prop1 value","Prop2":"prop2 value"}
So if the property doesn't have a public setter it is not serialized which doesn't seem normal as the Product class is used as output in this case.
I would suggest opening a connect ticket so that Microsoft can fix this before the release or at least tell that this is by design.
Perhaps there is an easy solution for my problem but I simply cannot seem to find it. I have read lots of tutorials about Knockout so I get the basics but I ask this question because my entity-structure is a bit more complicated than a person with a name and a list of friends which may or may not be on Twitter (Video on Channel9: Helping you build dynamic JavaScript UIs with MVVM and ASP.NET). Here's my situation:
I have a class PersonnelClass with this basic structure:
[Serializable]
//The interface is for the implementation of 'Name' and 'Description'
public class PersonnelClass : IPersonnelClassOrPerson
{
public PersonnelClass() : this(Guid.NewGuid(), "", "") { }
public PersonnelClass(Guid id, String name, String description = null)
{
if (id == Guid.Empty) { throw new ArgumentNullException("id"); }
Id = id;
Name = name;
Description = description;
Properties = new PropertyCollection();
}
public Guid Id { get; private set; }
public String Name { get; set; }
public String Description { get; set; }
public PropertyCollection Properties { get; private set; }
}
The PropertyCollection class and associated AbstractProperty class look like this:
[Serializable]
public class PropertyCollection: List<AbstractProperty> { }
[Serializable]
public abstract class AbstractProperty: IEntity, IProperty
{
public AbstractProperty(String name, String description = null) : this(Guid.NewGuid(), name, description) { }
public AbstractProperty(Guid id, String name, String description = null)
{
if (id == Guid.Empty) { throw new ArgumentNullException("id"); }
if (String.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); }
Id = id;
Name = name;
Description = description;
}
public Guid Id { get; private set; }
public String Name { get; private set; }
public String Description { get; private set; }
}
In my Controller, I create an instance of a PersonnelClassViewModel that has this structure:
public class PersonnelClassViewModel
{
public PersonnelClass PersonnelClass { get; set; }
public List<AbstractProperty> Properties { get; set; }
}
I fill this viewmodel with a new PersonnelClass and two test-properties to pass to my View like this:
var properties = new List<AbstractProperty>
{
new TextProperty("prop1", "descr1"),
new TextProperty("prop2", "descr2")
//TextProperty is derived from AbstractProperty
};
var vm = new PersonnelClassViewModel { Properties = properties };
return View(vm);
I get everything in my View as I wanted. From the View I want to create a new PersonnelClass with a set of selected properties. I have the fields for Name and Description and to add the properties I have a ListBox with the properties that already exist (for demo-purpose they came from the controller now). Through a bit of Knockout JavaScript code I can select items from this list and populate an HTML select-control () with the selected properties to add to the PersonnelClass. This all works fine, until I want to build up an object to pass back to the Controller and create the PersonnelClass.
My question is: what Knockout JS code is needed to build up this object and pass it to the Controller by submitting the form and in my Controller how should I receive this object, meaning: what type of object should this be (PersonnelClass, PersonnelClassViewModel, ...) ?
If any more info/code is needed, please do ask. Thanks in advance!
Update after answer of 'B Z':
I followed a few more of Steven Sanderson's tutorials about this to be sure I understand this, especially the one you provided in your answer. Now I have following code in my View to start with:
var initialData = #Html.Raw(new JavaScriptSerializer().Serialize(Model));
var viewModel = {
personnelClassViewModel : ko.mapping.fromJS(initialData),
properties : personnelClassViewModel.Properties,
selectedProperties : ko.observableArray([]),
addedProperties : ko.observableArray([])
};
ko.applyBindings(viewModel);
The variable 'initialData' contains the values I expect it to have but then I get the following error:
Microsoft JScript runtime error: 'personnelClassViewModel' is undefined
I have no clue anymore. Can anyone help me fix this?
Steven Sanderson has an example of how to to work with variable length lists and knockoutjs
http://blog.stevensanderson.com/2010/07/12/editing-a-variable-length-list-knockout-style/
Having said that, I think your problem isn't so much on the knockout side and more on the how to databind the data correctly on the server side. In the link above, Steven uses a FromJson attribute to model bind which you may find useful...
HTH