Serializing EF relationships in ASP NET - javascript

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.

Related

Replacing System.Windows.Forms.WebBrowser with Microsoft.Web.WebView2.WinForms.WebView2 in WinForms apps

I am upgrading a WinForms C# .NET 4.8 Framework application and replacing the embedded browser System.Windows.Forms.WebBrowser with Microsoft.Web.WebView2.WinForms.WebView2. I’m invoking some browser-hosted JavaScript functions from my C# code, and also my JavaScript functions do invoke some C# methods.
I’ve made it working (one of the information sources was the article https://weblog.west-wind.com/posts/2021/Jan/14/Taking-the-new-Chromium-WebView2-Control-for-a-Spin-in-NET-Part-1#do-you-need-the-webview2), however, I’m not feeling comfortable with the serialization/deserialization in my code. What bothers me is that the exchange is based on serialized strings; that approach appears somewhat primitive to me. To invoke a JavaScript function, I’m composing a source statement. Other way around, when my browser script is invoking a C# method, the argument is a serialized string (for which I know is JSON formatted) with all quote characters escaped.
My question is: should I have realized the interaction between C# and JavaScript in a different way?
Here are two C# code fragments with JavaScript invocation from a WinForms test program I’ve produced to cope with the migration:
public struct ConfigGraph3D
{
public bool showServices { get; set; }
public string viewStyle { get; set; }
public bool enforceNodeLabels { get; set; }
public bool enforceServiceLabels { get; set; }
public bool planesVisible { get; set; }
public bool embedded { get; set; }
}
// retrieving a JavaScript structure into a C# structure
//var CONFIG = { showServices: true, viewStyle: "O", enforceNodeLabels: false,
// enforceServiceLabels: false, planesVisible: true, embedded: false};
//
string invocation = "getConfig()";
string response = await browser.ExecuteScriptAsync(invocation);
// Notice here that I’m deserializing the data twice: first removing backslash escapes
// then converting it into the structure ConfigGraph3D.
string configStr = JsonSerializer.Deserialize<string>(response);
ConfigGraph3D config = JsonSerializer.Deserialize<ConfigGraph3D>(configStr);
textConfig.Text = response;
//
// sending a graph structure to JavaScript.
// The properly formatted JSON structure is read from a file by yet it needs to be serialized
// in order to add escape characters (backslash).
//
string invocation = getJsonFile (graphFilePath) ;
string response = await browser.ExecuteScriptAsync(invocation);
//
//
string getJsonFile (string graphFilePath)
{
string contents = File.ReadAllText(graphFilePath);
JsonSerializerOptions jso = new JsonSerializerOptions();
jso.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
string contents2 = JsonSerializer.Serialize(contents, jso);
string invocation = "replaceModelList(" + contents2 + ")";
return invocation;
}
Invoking C# from JavaScript example:
public struct ItemSelectedInfo
{
public int id { get; set; }
public string type { get; set; }
}
//
// invoked from JavaScript
// var jsonObj = "{ \"id\": " + mesh._id2 + ", \"type\":\"" + mesh._type + "\"}";
// window.chrome.webview.hostObjects.sync.dotnet.SelectedinGraphic(jsonObj);
//
[ComVisible(true)]
public class GraphInterface
{
public void SelectedinGraphic(string jsonInfo)
{
ItemSelectedInfo selectedNodeKey = JsonSerializer.Deserialize<ItemSelectedInfo>(jsonInfo);
Debug.WriteLine("SelectedinGraphic: " + jsonInfo);
}
}

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?

How to call page method with a parameter through in a javascript event?

I have method like this in my .cs :
[System.Web.Services.WebMethod]
public static void GetServiceInformation(IInfo x) //IInfo is an interface
{
x.l_power = true;
x.lb_InboxCount = UserTrans.GetInbox(int.Parse(emp_num), 0);
}
Now i want to call this method through a javascript method as a page method but it doesn't work .
<script type ="text/javascript">
function GetInfo() {
PageMethods.GetServiceInformation(this);
}
window.onload = setTimeout("GetInfo()", 3000);
</script>
<telerik:RadScriptManager ID="RadScriptManager1" runat="server" EnablePageMethods="true">
</telerik:RadScriptManager>
My .cs :
public partial class AppMaster : Log, IInfo //My page
{
public string Inbox
{
get
{
return hpl_Inbox.NavigateUrl;
}
set
{
hpl_Inbox.NavigateUrl = value;
}
}
public string Draft
{
get
{
return hpl_Draft.NavigateUrl;
}
set
{
hpl_Draft.NavigateUrl = value;
}
}
public string New
{
get
{
return hpl_New.NavigateUrl;
}
set
{
hpl_New.NavigateUrl = value;
}
}
public string Approved
{
get
{
return hpl_Approved.NavigateUrl;
}
set
{
hpl_Approved.NavigateUrl = value;
}
}
//------- etc
}
My interface :
public interface IInfo
{
string Inbox { get; set; }
string Draft { get; set; }
string New { get; set; }
string Approved { get; set; }
string archive { get; set; }
string search { get; set; }
string cand { get; set; }
string pri { get; set; }
string power { get; set; }
string admin { get; set; }
string help { get; set; }
bool l_cand { get; set; }
bool l_pri { get; set; }
bool l_power { get; set; }
bool l_admin { get; set; }
string lb_ApprovedCount { get; set; }
string lb_InboxCount { get; set; }
string lb_archive { get; set; }
string lb_DraftCount { get; set; }
}
function GetServiceInformation(x) {
$.ajax({
type: "POST",
url: "page.aspx/GetServiceInformation",
data: "{'x':'" + x + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: on_sucess,
error: on_error
});
function on_sucess(data, status) {
alert(data);
}
function on_error(request, status, error) {
alert(error);
}
}
Sorry, if it doesn't work
Answer Edit Based On Chat Discussion
First, thanks for clarifying your question. It was bit hard to understand the problem you were trying to solve. The reason? Because your code wasn't clear enough and that usually happens when there are design issues. That's effectively what your facing here a bit of a design issue. First, I'll point out some mistakes...
In this javascript function...
function GetInfo() {
PageMethods.GetServiceInformation(this);
}
this is NOT an instance of your page. So there's no use to make your page implement an interface...
public partial class AppMaster : Log, IInfo{}
and expect that a javascript call would page an instance of System.Web.UI.Page to your class (not to mention an implementation of the IInfo interface). You can blindly ditch this approach because it's a permanent design issue and it's not even going to work.
Now, if what you want is to serve the page, then do some further processing and finally send the results of this processing back to the client asynchronously using javascript/ajax you have a couple of approaches here:
Using SignalR which is my favourite approach (but you already stated your solution doesn't meet the requirements to use SignalR)
Using jQuery ajax which is also a very valid approach
Now, I'll explain the second approach
Using jQuery Ajax
Simply render the page as you would normally do in ASP.NET. Then on the client-side, when the page loads, make an ajax request to start processing the information you want to display. You can start the request as soon as the page loads to make the processing on the server
$(function(){
$.ajax({
type: 'POST',
url: 'AppMaster.aspx/GetServiceInformation',
data: "{}",
contentType: 'application/json;charset=utf-8',
dataType: 'json',
success: function(d) {
//load data received
},
error: function() {
//process the error
}
});
});
In the success handler you need to load the values received from the ajax call on your web controls. Then change your IInfo interface to a concrete object in a separate code file. But, remember that this class should NOT hold any references whatsoever to your web controls
public class JSInfo
{
string Inbox { get; set; }
string Draft { get; set; }
string New { get; set; }
string Approved { get; set; }
string archive { get; set; }
string search { get; set; }
string cand { get; set; }
string pri { get; set; }
string power { get; set; }
string admin { get; set; }
string help { get; set; }
bool l_cand { get; set; }
bool l_pri { get; set; }
bool l_power { get; set; }
bool l_admin { get; set; }
string lb_ApprovedCount { get; set; }
string lb_InboxCount { get; set; }
string lb_archive { get; set; }
string lb_DraftCount { get; set; }
}
then change your page method to...
[System.Web.Services.WebMethod]
public static JSInfo GetServiceInformation()
{
//you need to get the emp_num from session
//construct the JSInfo object
JSInfo info = new JSInfo();
//get the data from the database
var data = UserTrans.GetInbox(int.Parse(emp_num), 0);
//set the properties of the JSInfo...similar to the line below for each property...Draft, New, Approved, etc
info.Inbox = data.Inbox;
//return the object to the client
return info;
}
Notice that you need to get the emp_num value from Session since you stated in the chat discussion that this value comes from a Session variable. Now, going back to the success handler of your jQuery ajax call which executes soon after the response is received back from the server. You will receive a json object in the handler parameter d with the properties of the JSInfo class that you just sent from the server. Then you set the controls on the page...
success: function(d) {
$('#id_inbox_control').val(d.Inbox);
$('#id_draft_control').val(d.Draft);
$('#id_new_control').val(d.New);
//and keep doing the same for the rest of the controls
},
That should be a neater solution. Of coure, I cannot cover every single details here. But for sure you will get the idea. If not, let me know if I need to expand on something.
If your page implements the interface, you don't have to pass it! In your c# code write:
this.l_power=true;
If you need to pass values from JavaScript to page method, define each property as a parameter and pass values to the page method:
[System.Web.Services.WebMethod]
public static string GetServiceInformation(int value1, string value2)
{
l_power = value1;
something = value2;
return "some string to indicate the result of call";
}
And:
<script type ="text/javascript">
var v1 = 15;
var v2 = "some value";
function GetInfo() {
PageMethods.GetServiceInformation(v1, v2, success, fail);
}
window.onload = setTimeout("GetInfo()", 3000);
</script>
in which success and fail are the names of two JS functions that will be called after the request is completed. Note that a page method can return a string value to inform the client about what happened on the server.
I can only think of one method.
You should somehow marshal the this object, and send it as parameter. I mean you should write a method that marshalls an object to equivalent json or xml, and POST that to your server.
I believe you can do it as you did above only through a clean API and compiler tool between C# and javascript to implement RPC just like GWT was written for java and javascript.
Can you do a little test?
Declare a public class JSInfo: IInfo{} in your page code, and in your web method declare that parameter of yours as JSInfo.
As JSInfo implements IInfo, your program logic can work with it without any problem.
Just to let you know, your code does not work because you cannot serialize interfaces as they
are not concrete types, if you think about it, interfaces have no real correlation in XML schema. There's no way to represent the data. Base classes will work however.
If you fill bad in declaring the JSInfo in the asp.net page class, then create a class called
WebMethodsHelper and declare your JavaScript WebMethod Interfaces (Adaptors) there.
public class JSInfo: IInfo{
private ControlsCollection controls;
public JSInfo(ControlsCollection constrols){
this.controls = controls
FillObjects();
}
private void FillObjects(){
//iterate through controls and extract you data to you
//class properties/fields
}
public void Update(ControlsCollection controls){
this.controls=controls;
FillObjects();
}
public void Update(JSInfo info, ControlsCollection controls){
this.controls=controls;
//populate your object based on info
//then extract data from page controls
FillObjects();
}
}
public class MyPage: System.Web.UI.Page{
protected void Page_Load(object sender, EventArgs e){
if(!IsPostBack && Session["info_obj"])
Session["info_obj"] = new JSInfo(this.Controls);
}
[System.Web.Services.WebMethod]
public static string GetServiceInformation(JSInfo data)
{
JSInfo info = new JSInfo(this.Controls);
info.Update(data);
//or if you stored the info in the session
JSInfo info = (JSInfo)Session["info_obj"];
info.Update(this.Controls, data);
}
}
The JSInfo is just to give your IInfo interface some structure so it can be serialized.
From JavaScript you should be able to call you page method like this:
<script type ="text/javascript">
function GetInfo() {
var info = new JSInfo();
info.PropertyXPTO="something";
PageMethods.GetServiceInformation(info, onSuccess, onError);
}
function onSuccess(result) {
alert(result);
}
function onError(result) {
alert('error: ' + result);
}
window.addEventListener("load", function(){
setTimeout("GetInfo()", 10 * 1000);
}, false);
</script>
Not that you should have a ScriptManager at the top of your page
<asp:ScriptManager ID="ScriptManager1" EnablePageMethods="true" runat="server" />
The ScriptManager is responsible for giving you the PageMethods class in the JavaScript, along
with other things.
Also, confirm the following:
The page method must have the System.Web.Services.WebMethod attribute. [WebMethod]
The page method must be public. [WebMethod] public ...
The page method must be static. [WebMethod] public static ...
The page method must be defined on the page (either inline or in the code-behind). It cannot be defined in a control, master page, or base page.
The ASP.NET AJAX Script Manager must have EnablePageMethods set to true.
function GetServiceInformation(x) {
$.ajax({
type: "POST",
url: "page.aspx/GetServiceInformation",
data: x, //Attention: there is no {}
contentType: "application/json; charset=utf-8",
dataType: "json",
success: on_sucess,
error: on_error
});
function on_sucess(data, status) {
alert(data);
}
function on_error(request, status, error) {
alert(error);
}
}
And then
<script type ="text/javascript">
function GetInfo() {
var myInfo = {
Inbox: "",
Draft: "",
New: "",
l_cand: ""
......//Attention, you should make this class corresponding to your server class IInfo
};
PageMethods.GetServiceInformation(myInfo);
}
window.onload = setTimeout("GetInfo()", 3000);
Referred to #anotherdie. And tell you how to transfer "X"
In your .js
function GetInfo() {
var parameter = {};
parameter.name = "test";
parameter.id = 123;
parameter.state = true;
PageMethods.GetServiceInformation(parameter,
function (res) {
if (res == true) {
//do some
alert("ok");
} else {
//do some
alert("bad");
}
}, function(err){
alert("ERROR: "+err._message);
});
}
in your apsx.cs (you can return a string, a list, a bool, an int or a json object //for json use json.net http://james.newtonking.com/json) for this i'll return a bool.
using System.Web.Services;
[WebMethod]
public static bool GetServiceInformation(ClassData parameters)
{
try
{
//do some
return true;
}
catch(Exception ex)
{
return false;
}
}
in a interface ClassData .cs
public string name { get; set; }
public int id { get; set; }
public bool state { get; set; }
public ClassData(){}
public ClassData(string _name, int _id, bool _state)
{
this.name = _name;
this.id= _id;
this.state = _state;
}
I do the following :
Create New Page and called it : Counts.aspx
protected void Page_Load(object sender, EventArgs e)
{
emp_num = int.Parse(Session["empnum"].ToString());
Thread.Sleep(3000);
string res = GetCounts(emp_num);
Response.Write(res);
}
/***********************************************************************************************/
protected string GetCounts(int empNum)
{
string outbox = UserTransaction.getoutboxCount(empNum, 0);
string inbox = UserTransaction.getinboxCount(empNum, 0);
string archive = UserTransaction.getarchivecount(empNum, 0);
string draft = UserTransaction.getdraftcount(empNum, 0);
return outbox + "~" + inbox + "~" + archive + "~" + draft + "~";
}
and in my main page :
<script type="text/javascript">
function loadXMLDoc() {
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}
else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var split = xmlhttp.responseText.split('~');
var outbox = split[0];
var inbox = split[1];
var archive = split[2];
var draft = split[3];
document.getElementById("lbl_DraftCount").innerHTML = draft;
document.getElementById("lbl_InboxCount").innerHTML = inbox;
document.getElementById("lbl_ApprovedCount").innerHTML = outbox;
document.getElementById("lbl_archive").innerHTML = archive;
}
}
xmlhttp.open("GET", "Counts.aspx", true);
xmlhttp.send();
}
loadXMLDoc();
</script>

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