How to call asmx webservice for collection using BackboneJs - javascript

I hope someone could put me through a code to learn to call asmx webservices from backbone collection. The example i have put here is extremely simple
Collection
window["Persons"] = Backbone.Collection.extend({
model: Person,
url: "service.asmx/GetPeople"
});
note: I do have a service.asmx file at the point
Asmx End point
[WebMethod]
[ScriptMethod]
public static List<Person> GetPeople()
{
List<Person> people = new List<Person>(10);
for (int i = 0; i < 10; i++)
{
people.Add(new Person(i.ToString()));
}
return people;
}
The Model
public class Person
{
public string Name { get; set; }
public Person(string name)
{
Name = name;
}
}
when i do the below chrome xhr inspector informs me of this error
var family = new Persons();family.fetch();
Request format is unrecognized for URL unexpectedly ending in
'/GetPeople'

You will want to override the Backbone.sync() function to customize the persistence and retrieval of models from the server.
You can take a look at the annotated source code of how the Backbone.sync() function is overwritten for a local storage alternative.

Related

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.

ASP.NET MVC - How to "reverse" model binding to convert a C# model back to a query string representation

I have a custom javascript on the client side that I use to build up a querystring and pass over to my asp.net-mvc controller
var templateQueryString = BuildTemplate();
$.ajax({
url: '/MyController/Save?' + templateQueryString,
type: 'post',
dataType: 'json',
success: function (data) {
}
}
and on my controller all of the properties leverage the model binding so it comes in as a single object on the server side. NOTE: that this is a pretty complex object with arrays and arrays of sub objects:
public ActionResult Save(MyTemplate template)
{
}
the issue now is that I need to be able to convert from my C# object back to a string that represents "myTemplateQueryString" on the client side.
Is there any recommended way to take an object and do the "reverse" model binding. They key here is that it generates a string that I could use as a query string again in the future to pass into another asp.ent-mvc controller action.
Here is an example of the querystring that I am storing locally:
<input type="hidden" value="showIds=false&showRisks=false&
amp;statusIds=2&statusIds=1&statusIds=6&statusIds=8&
amp;statusIds=3&statusIds=9&showCompleted=0"
name="filterQueryString" id="filterQueryString">
As #haim770 said it would be easier if you used JSON in the request payload, and not the query string to pass your complex object to the server.
Regarding creating the query string from a model there is not a built-in method that does something like that or any recommended approach as far as i know. An obvious solution is to use reflection and build the query string from your properties.
Assuming your BuildTemplate class looks something like:
public class BuildTemplate
{
public bool ShowIds { get; set; }
public bool ShowRisks { get; set; }
public bool ShowCompleted { get; set; }
public int[] StatusIds { get; set; }
}
You can develop an extension method to convert any object to a QueryString. Here is some initial code you can start with:
public static class ObjectExtensions
{
public static string ToQueryString(this Object obj)
{
var keyPairs = obj.GetType().GetProperties().Select(p =>
new KeyValuePair<string, object>(p.Name.ToLower(), p.GetValue(obj, null)));
var arr = new List<string>();
foreach (var item in keyPairs)
{
if (item.Value is IEnumerable && !(item.Value is String))
{
foreach (var arrayItem in (item.Value as IEnumerable))
{
arr.Add(String.Format("{0}={1}", item.Key, arrayItem.ToString().ToLower()));
}
}
else
arr.Add(String.Format("{0}={1}", item.Key, item.Value.ToString().ToLower()));
}
return "?" + String.Join("&", arr);
}
}
Then you can easily invoke this code on any object to generate a query string:
var person = new BuildTemplate() { StatusIds = new []{ 1, 5, 8, 9 }, ShowRisks = true };
var queryString = person.ToQueryString();
This would generate a query string like:
"?showids=false&showrisks=true&showcompleted=false&statusids=1&statusids=5&statusids=8&statusids=9"
This query string should work just fine with the default model binder for the BuildTemplate class.

How to get Data from Model to JavaScript MVC 4?

that's my function:
<script> function Calculate()
{
var ItemPrice = document.getElementById("price");
var weight = document.getElementById("weight");
var SelWeight = weight.options[weight.selectedIndex].value;
alert(SelWeight);
var Category = document.getElementById("SelectedCategory");
var SelCategory = Category.options[Category.selectedIndex].value;
alert(SelCategory);
}
</script>
i want to get SelCategories.Tax and SelCategories.Duty to add them to weight value and total price to show the total in a label.. I'm using ASP.NET MVC 4 and this is my Model that i want to use
public class CategoriesModel
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public decimal Duty { get; set; }
public decimal Tax { get; set; }
public IEnumerable<SelectListItem> CategoriesList { get; set; }
}
I think the best approach here is to use Json and something like Vue.js, Knockout.js, etc. (but also you can do it without these libraries, if your case is simple).
First, you need to install Json support with a command in PM console:
PM> install-package NewtonSoft.Json
Then, in your view you can convert your model to javascript object like this:
#model ...
#using Newtonsoft.Json
...
<script type="text/javascript">
var data = #Html.Raw(JsonConvert.SerializeObject(this.Model));
</script>
Then you can access all the properties in your model with in plain JavaScript:
var id = data.CategoryID;
That's it! Use knockout (update 2018: this is obsolete, there is no reason you should use knockout now) if your logic is complicated and you want to make your view more powerful. It could be a little bit confusing for newbie, but when you get it, you'll gain the super-powerful knowledge and will be able to simplify your view code significantly.
You need to create actions (methods in the controller) that return JsonResult.
From the client side, make ajax calls to the server to recover and use that data. The easiest way to do this is to use any of the jQuery ajax methods.
public JsonResult GetData(int id)
{
// This returned data is a sample. You should get it using some logic
// This can be an object or an anonymous object like this:
var returnedData = new
{
id,
age = 23,
name = "John Smith"
};
return Json(returnedData, JsonRequestBehavior.AllowGet);
}
When you use a jQuery get to the /ControllerName/GetData/id, you'll get a JavaScript object in the success callback that can be used in the browser. This JavaScript object will have exactly the same properties that you defined in the server side.
For example:
function getAjaxData(id) {
var data = { id: id };
$.get('/Extras/GetData/1', // url
data, // parameters for action
function (response) { // success callback
// response has the same properties as the server returnedObject
alert(JSON.stringify(response));
},
'json' // dataType
);
}
Of course, in the success callback, instead of making an alert, just use the response object, for example
if (response.age < 18) { ... };
Note that the age property defined in the server can be used in the JavaScript response.
If you prefer a class try jsmodel. After converting the mvc view model to javascript it adds the benefit of retrieving DOM updates.
var jsmodel = new JSModel(#Html.Raw(Json.Encode(Model)));
Then anytime you want to get the latest state of the DOM do this to update your variable:
var model = jsmodel.refresh();
Website:
http://chadkuehn.com/jquery-viewmodel-object-with-current-values/
There is also a nuget:
https://www.nuget.org/packages/jsmodel/
var errors = '#Html.Raw(Json.Encode(ViewData.ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage)))';
var errorMessage=JSON.parse(errors);

How to consume a complex type returned by a WebMethod on client side using Javascript?

Iam a beginner with Webmethods and Services an I have landed in a situation here.
I have a webmethod that returns an instance of StatusViewModel class..
[WebMethod()]
public static StatusViewModel GetTime1()
{
Debug.Write("Timer");
StatusViewModel statusViewModel = new StatusViewModel();
statusViewModel.Label1 = "aaa";
statusViewModel.Label1 = "bbb";
statusViewModel.ListBox.Add("1", "ccc");
statusViewModel.ListBox.Add("2", "ccc");
return DateTime.Now.ToString();
}
StatusViewModel class looks like this one
public class StatusViewModel
{
public string Label1 { get; set; }
public string Label2 { get; set; }
public IDictionary<string, string> ListBox { get; set; }
}
How should I consume this method and set 2 labels and list-box with the data received from the method ?
Usually this is how I call webmethod
$(document).ready(function() {
call1();
});
function OnSuccess1(result, ctrl) { $('#<%=Label2.ClientID %>').html(result); }
function OnError1() { alert("error!"); }
function call1() { PageMethods.GetTime1(OnSuccess1, OnError1); }
This works if the return type is String.
Can any one suggest any simple articles regarding this topic ?
That one, could be nice for start.
http://encosia.com/using-jquery-to-consume-aspnet-json-web-services/
It gives you information, rest - just google and try something by your self. It is easy and very common task.
try converting your class to JSON. Then you can read it easily in javascript

Categories

Resources