javascript call MVC Controller parameter always null when object field is private - javascript

I use javascript to call controller to process a function.
The parameter value (name in summary) is null when the field is set to private.
It works when the field is set to public.
Is set to public the only way? or there is a better way to do it?
thanks in advance.
My object
[DataContract]
public class Summary
{
[DataMember]
public int id { private set; get; }
[DataMember]
public string name { private set; get; }
public summary() {}
public summary(int id, string name)
{
id = id;
name = name;
}
}
MVC Controller
public ActionResult SetSummary(Summary summary)
{
string anme = summary.name; **<-- null if private**
...
}
Javascript
$http.post("MyController/SetSummary", JSON.stringify({
summary: mySummaryObject}))
.success(function (data, status, headers, config) {
....
}

yup, it should be public because defaultmodelbinder Maps a browser request to a data object. This class provides a concrete implementation of a model binder.
The DefaultModelBinder class maps the following types of objects to a browser request:
Primitive types, such as String , Double, Decimal , or DateTime objects.
Model classes, such as Person, Address, or Product.
Collections, such as ICollection, IList, or IDictionary.
Source: https://msdn.microsoft.com/en-us/library/system.web.mvc.defaultmodelbinder(v=vs.118).aspx
Hope it was useful kindly let me know your thoughts or feedbacks
Thanks
Karthik

Related

How To Send Request To C# Method And Get Its Parameters by Jquery

Is there any way to call an API to know its required parameters?
for example, if there is a controller has a method takes a name and date as a parameters
[HttpPost]
public string testUrl(string name,string date)
{
return "success";
}
now what I am trying to do is to make a dynamic form take an API URL and generate all required inputs so I have to find some way to call the URL and return the required parameters.
The quick and dirty way would be to just hard code it:
[HttpPost]
public string testUrl(string name,string date)
{
return "success";
}
public APISchema TestUrlSchema(){
return new APISchema() {
Parameters = new List<Parameter>(){
new Parameter(){ Name = "name", Type = "String" },
new Parameter(){ Name = "date", Type = "String" }
}
};
}
public class APISchema {
public List<Parameter> Parameters {get;set;}
}
public class Parameter {
public String Name {get;set;}
public String Type {get;set;}
}
You could use Reflection to auto-generate this if you want to do it for a large number of actions.
As comments have mentioned, there are libraries Swagger which will do this for you.

How can I send a date using a AXIOS Get?

I need to send a date like
2007/08/01 00:00
as one of the values in my AXIOS GET
https://restapi.azurewebsites.net/api/PublicationReport/" +
dbid +
"/" +
sortDate
As you can tell it plays havoc with the Web API controller
<Route("api/PublicationReport/{dbid}/{sortDate}")>
The controller thinks that every "/" is a new parameter.
Is there a special format that must be used or do I need to send it as a json object?
I went with
params: {
dbid: dbid,
sortDate: sortDate
},
on the client side and below for the server side
Public Function GetValues(dbid As Integer, sortDate As String) As String
You can just create an object like this:
public class SomeQuery
{
public string SomeParameter { get; set; }
public int? SomeParameter2 { get; set; }
}
And then in controller just make something like that:
[HttpGet]
public IActionResult FindSomething([FromQuery] SomeQuery query)
{
// Your implementation goes here..
//then you can access query value using HttpContext.Request.Query
}
or using method params
[HttpGet]
public IActionResult FindSomething(string value1, string value2)

Serializing EF relationships in ASP NET

I am trying to create a simple application in WebApi with the following classes.
Author and Book, the Author has the following attributes.
public class Author
{
public int AuthorId{ get; set; }
public string Name { get; set; }
public virtual List<Book> Books { get; set; }
}
Book has the following attributes.
public class Book
{
public int BookId{ get; set; }
public string Title{ get; set; }
public virtual Author Author{ get; set; }
}
I have a db context that looks like this
public class DatabaseContext : DbContext
{
public DatabaseContext() : base("dbCon")
{
Database.CreateIfNotExists();
Configuration.ProxyCreationEnabled = false;
}
public DbSet<Author> Authors { get; set; }
public DbSet<Books> Books { get; set; }
}
In my view I am trying to display all authors and their related books. This is my js code.
function getData() {
$.ajax({
url: '/api/Author',
type: 'GET',
dataType: 'json',
contentType: 'application/json',
success: function (data) {
console.log(data);
showData(data);
}
});
}
function showData(data) {
var string = '';
$.each(data, function (i, a) {
string += '<h1>Question title: ' + a.Name + '</h1>';
$.each(q.Books, function (j, b) {
string += '<p>' + b.Title + '</p><br>';
});
});
$('.divclass').html(res);
}
Controller method that returns all authors with related books.
public List<Author> Get()
{
return db.Authors.Include(a => a.Books).AsNoTracking().ToList();
}
When I am trying to run the project I get an error in my console.
The following error says:
Object graph for type 'System.Collections.Generic.List`1[[WebApplication1.Models.Books, WebApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' contains cycles and cannot be serialized if reference tracking is disabled. And the exception type is System.Runtime.Serialization.SerializationException.
I use code first migrations to seed the database and I know that the db is not empty. How do I fix this? And whats wrong?
As the error message tells you, your data model has cyclic references. Specifically, your Book class has a reference to the Author class and Author has a reference back to Book. You can break the cycle, if you don't serialize the book's author (you are coming from the author in your object tree, so this information is not lost). You can do that with the ScriptIgnoreAttribute:
public class Book
{
public int BookId{ get; set; }
public string Title{ get; set; }
[ScriptIgnore]
public virtual Author Author{ get; set; }
}
Another option would be to change the JSON serialization settings, as described in this Q&A.
Part of the problem is the Entity Framework's lazy loading, where it goes out and asks the database for the data whenever a reference property is accessed. This is handy for your own code, but JSON serialization will read every property.
So for each Author record, it reads the Books list, which you had already asked for. Then when it goes through each of those books, it hits each book's Author property and asks the database for the author information. Then when it goes through the properties of that Author it hits the Books property and asks the database for all the books by that author. This would repeat forever, but it's smart enough to just stop and throw that exception.
So another way to take care of this is to disable lazy loading whenever you return an Entity type. Something like this:
public List<Author> Get()
{
db.Configuration.LazyLoadingEnabled = false;
return db.Authors.Include(a => a.Books).AsNoTracking().ToList();
}
This way, it only serializes the data that is already downloaded from the database. So in this case, when it serializes each book, it sees the Author property, sees that it's null and just moves on.

How to pass complex objects in SignalR with proper casing?

I have a complex class like this in my c#:
public class Channel
{
public int Id { get; set; }
public string ChannelName { get; set; }
public Dictionary<int, Question> Questions { get; set; }
public Dictionary<int, ChatMessage> ChatMessages { get; set; }
public Dictionary<int, User> Users { get; set; }
public bool IsAdmin { get; set; }
public int TimeLeft { get; set; }
}
To pass it to my client i do:
Clients.Caller.CheckVersion(ChannelInstance);
My problem is that when i recieve the object on my client it will still have CamelCasing, instead of camelCasing. Is there any way to do this, so SignalR will automatically convert my object into an object with proper variable casing?
I know it's a pretty petty something, but i find it pretty annoying to have a class defined like this in my javascript:
function Channel() {
this.Id;
this.ChannelName;
this.etc;
}
when this looks much more JavaScript correct:
function Channel() {
this.id;
this.channelName;
this.etc;
}
Is there any way to do this, or will I just have to make do with the odd CamelCasing?
As Rob Segerink states in this answer, it's apparently not possible to change the global JsonSerializerSettings without breaking SignalR. A quick search of the source reveals that it sometimes does new JsonSerializer() and sometimes JsonSerializer.CreateDefault(), which might be causing at least part of the problem.
That being said, you may be able to adopt the trick from the question SignalR Typenamehandling to your needs, in particular to override Json.NET's behavior and use camel casing only for types marked with a specific attribute, or in assemblies marked with a specific attribute, using the following contract resolver:
public sealed class ConditionalCamelCaseContractResolver : IContractResolver
{
readonly static IContractResolver defaultContractResolver;
readonly static IContractResolver camelCaseContractResolver;
readonly static ConcurrentDictionary<Type, bool> camelCaseTable;
static Func<Type, bool> isCamelCase;
// Use a static constructor for lazy initialization.
static ConditionalCamelCaseContractResolver()
{
defaultContractResolver = new JsonSerializer().ContractResolver; // This seems to be the only way to access the global singleton default contract resolver.
camelCaseContractResolver = new CamelCasePropertyNamesContractResolver();
camelCaseTable = new ConcurrentDictionary<Type, bool>();
isCamelCase = (t) => GetIsCamelCase(t);
}
static bool GetIsCamelCase(Type objectType)
{
if (objectType.Assembly.GetCustomAttributes<JsonCamelCaseAttribute>().Any())
return true;
if (objectType.GetCustomAttributes<JsonCamelCaseAttribute>(true).Any())
return true;
foreach (var type in objectType.GetInterfaces())
if (type.GetCustomAttributes<JsonCamelCaseAttribute>(true).Any())
return true;
return false;
}
static bool IsCamelCase(Type objectType)
{
var code = Type.GetTypeCode(objectType);
if (code != TypeCode.Object && code != TypeCode.Empty)
return false;
return camelCaseTable.GetOrAdd(objectType, isCamelCase);
}
#region IContractResolver Members
public JsonContract ResolveContract(Type type)
{
return IsCamelCase(type) ? camelCaseContractResolver.ResolveContract(type) : defaultContractResolver.ResolveContract(type);
}
#endregion
}
[System.AttributeUsage(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Interface)]
public class JsonCamelCaseAttribute : System.Attribute
{
public JsonCamelCaseAttribute()
{
}
}
Next, mark your assemblies, types or interfaces with this attribute to enable camel casing:
[assembly: MyNamespace.JsonCamelCaseAttribute]
Finally, install the contract resolver with the techniques shown in that question using the following settings:
public static class ConverterSettings
{
public static JsonSerializer GetSerializer()
{
return JsonSerializer.Create(new JsonSerializerSettings()
{
ContractResolver = new ConditionalCamelCaseContractResolver()
});
}
}
Since SignalR's own internal types will not be so marked, they will continue to be serialized using default settings.
Note - tested with various test cases but not SignalR itself since I don't currently have it installed.
No, you can't, when you change the default JSON.net serialize settings on the server, by using the JsonSerializerSettings class, the SignalR jquery client will stop working because it expects it's server messages to be serialized by using the default JSON.net serialize settings. I believe in version 3 they will change this.
I know this is an old question but this quick solution might help someone coming across this problem. It certainly has helped me in the past.
The DataContract and DataMember attributes might be exactly what your a looking for to serialize your class in the way you want and still keep it upper case letter in C#.
Your class would look like this:
[DataContract]
public class Channel
{
[DataMember(Name = "id")]
public int Id { get; set; }
[DataMember(Name = "channelName")]
public string ChannelName { get; set; }
[DataMember(Name = "questions")]
public Dictionary<int, Question> Questions { get; set; }
...
}
This will serialize it just the way you want it.

Unable to send JSON data to MVC controller

I have a JavaScript function that looks as follows:
function exportToExcel() {
$.ajax({
url: "/eBird/ExportToExcel",
data: jsonSightingData,
type: 'POST',
contentType: 'application/json'
});
}
My MVC controller looks like this:
public ActionResult ExportToExcel(List<Entities.MyClass> data)
{
try
{
...
}
catch (System.Exception exception)
{
...
}
MyClass defintion is:
public class MyClass
{
public string comName { get; set; }
public int howMany { get; set; }
public double lat { get; set; }
public double lng { get; set; }
public string locID { get; set; }
public string locName { get; set; }
public bool locationPrivate { get; set; }
public string obsDt { get; set; }
public bool obsReviewed { get; set; }
public bool obsValid { get; set; }
public string sciName { get; set; }
}
The class matches the JSON data coming in exactly. The problem is that when my controller method is called, 'data' is always NULL. My understanding was that the MVC model binder would automatically bind the JSON data to my MyClass list. But it doesn't appear to be working.
Sample JSON is as follows:
[{"comName":"Great Black-backed Gull","lat":42.4613266,"lng":-76.5059255,"locID":"L99381","locName":"Stewart Park","locationPrivate":false,"obsDt":"2014-09-19 12:40","obsReviewed":false,"obsValid":true,"sciName":"Larus marinus"}]
Use a General Object (Like JContainer) to "capture" the incoming data. or even Object if you are not sure what you get.
Then see what you have inside.
I use an external deserializer to convert json back to class. (using .ToString() to make it readable to the serializer)
(try Json.Net)
Also - make sure that the JSON is not converted into Unicode. I've had an issue with that as well.
another remark - I think content type should be application/json.
Read this: SO about json content type
Run Fiddler and capture Json sent to controller. The controller expects a List but looks like you are sending single object. Stuff coming in as null happens to many of us. I'll try and run what you have. Can you also mess with controller and give it just MyClass coming in?

Categories

Resources