I'm building a small test prototype where I'm pulling data from a back-end SQL database using a repeater and an entity data source. One of my columns returns data in JSON format.
Question: is there any way to parse JSON data within a repeater (or, for that matter, any other ASP.NET data control)? I was hoping that there'd be a relatively easy way to do this, but I'm discovering that's not the case.
Thanks in advance!
You can parse the JSON data, but the real question is where you want to parse it; on the client or on the server? Assuming you want to parse the data on the server, you can use the ItemDataBound event and the JavaScriptSerializer class:
using System.Web.Script.Serialization;
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
var jsonData = (string)DataBinder.Eval(e.Item.DataItem, "JsonData");
var jss = new JavaScriptSerializer();
var dict = jss.Deserialize<Dictionary<string,dynamic>>(jsonData);
}
Related
I am creating a VB 2010 desktop application. I use the lines below to get a string response from an aspx page that I use to collect online data for the application.
Dim response As Byte() = myWebClient.UploadValues(myWeb & "/Default.aspx", "POST", nmv)
dim str as string = Replace(System.Text.Encoding.ASCII.GetString(response), "<(.|\n)*?>", "")
System.Text.Encoding.ASCII.GetString(response)
'nmv' is a defined NameValueCollection variable
Now I need to get this data back from the aspx page as either as nmv or a datatable. Is that possible? How could I go about doing it? I am thinking the key is in the System.'Array'... or something but I can't figure it out and I don't get any search results on the web.
Getting the data back as a string array is good for me, getting it nmv is even better; but getting it back as a DataTable would be perfect! I am able to deal with the aspx page giving back the data in any format, I just need the vb app to know how to collect it.
Thank you
You can change the content type of the aspx from text to image or pdf etc. but not a complex datatype.
I would use a web service or wcf service instead. You can just declare a method of DataTable type and you're done.
http://msdn.microsoft.com/en-us/library/ms972326.aspx
Maybe easiest way would be to use *.ashx Http Handler (generic handler) and save DataTable to XML, something like this :
Server:
public class Handler1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
/// if needed request data is in context.Request
DataTable tbl = GetDataTable();
/// table must have name, if not WriteXml will fail
tbl.TableName = "TableName";
tbl.WriteXml(context.Response.OutputStream);
}
public bool IsReusable
{
get
{
return false;
}
}
Then on client you should use ReadXml DataTable method to populate DataTable on client.
I have a Data Repeater hooked up to a datasource (datatable object). I need to change the output on the frontend for certain columns under certain conditions. What would be the most efficient way to do this?
I am currently trying to create the formatted output and assign it to another datatable and use that as the data source, but it seems overly complicated and something that would be hard to maintain.
Is there an easier way to manipulate column values for a datasource? I need the ability to check the previous and next rows for the source as that is a basis for some of the column values.
If you're talking about simple manipulation, the DataBinder.Eval method accepts a format string:
<%#Eval("SomeMoneyColumn", "{0:C}")%>
If the format string is not sufficient, you could create a method in the code-behind to handle the formatting, like this:
<%#FormatData(Eval("SomeColumn"))%>
In code-behind:
protected string FormatData(object data)
{
return String.Format("My name is {0}", data);
}
You can also use the ItemDataBound event too. Using this technique, you can still access the datasource object, in the case that your manipulation involves other data that is bound to the repeater.
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
Label lblCtrl = e.Item.FindControl("SomeControl") as Label;
if (lblCtrl != null)
{
lblCtrl.Text = String.Format("My name is {0}", DataBinder.Eval(e.Item.DataItem, "SomeColumn"));
}
}
I don't think there's a way to do what you want on the client side easily w/o using special logic like you are doing now. If you are getting data from a database, you could potentially do all the data manipulation on the DB side and pass it along transparently to the front end.
So, there are a wealth of Flex articles online about how to handle a .NET WebMethod that returns a DataSet or DataTable. Here is an example:
Handling web service results that contain .NET DataSets or DataTables
So, I know how to use result.Tables.<tablename>.Rows and the like. But what I cannot seem to figure out or find online is how to go the other direction - a method to pass objects or tables back to the .NET Webservice from Flex, without stooping to passing XML as a string, or making huge web service methods that have one parameter for each property/column of the object being stored. Surely others, smarter than I, have tackled this issue.
I am using ASP.NET 2.0 Typed DataSets, and it would be really nice if I could just pass one object or array of objects from Flex to the web service, populate my Typed DataTable, and do an Update() through the corresponding typed TableAdapter. My dream would be a [WebMethod] something like one of these:
public void SaveObject(TypedDataTable objToSave) { ... }
public void SaveObject(TypedDataSet objToSave) { ... }
I've had the typed datatables saving to the database, I know how to do that part and even a few tricks, but we had XML being passed back-and-forth as a string - eww. I'm trying to get to a more object-based approach.
The best object based approach is AMF. I assume its probably a bit late in your your development cycle to change your integration layer, but otherwise I dont know of a way to get around marshalling your object(s) back into XML or separating them out into their primitive components.
For .NET implementations of AMF check out:
FlourineFX(FOSS)
WebORB for .NET
Its amazing how easy things become once AMF is used, for example using the Mate MVC framework and an AMF call passing a complex object to the server looks something like this:
<mate:RemoteObjectInvoker instance="yourWebservice" method="saveComplexObject" showBusyCursor="true" >
<mate:resultHandlers>
<mate:CallBack method="saveComplexObjectSuccess" arguments="{[resultObject]}" />
</mate:resultHandlers>
<mate:faultHandlers>
<mate:MethodInvoker generator="{DataManager}" method="presentFault" arguments="{fault}" />
</mate:faultHandlers>
</mate:RemoteObjectInvoker>
With result and fault handlers being optional.
The direction I ended up going was close to what I hoped was possible, but is "hack-ish" enough that I would consider SuperSaiyen's suggestion to use AMF/ORM a better solution for new/greenfield projects.
For sake of example/discussion, let's say I am working with a Person table in a database, and have a typed DataSet called PeopleDataSet that has PersonTableAdapter and PersonDataTable with it.
READ would look like this in .NET web service:
[WebMethod]
public PeopleDataSet.PersonDataTable GetAllPeople() {
var adapter = new PersonTableAdapter();
return adapter.GetData();
}
... which in Flex would give you a result Object that you can use like this:
// FLEX (AS3)
something.dataProvider = result.Tables.Person.Rows;
Check out the link I put in the question for more details on how Flex handles that.
CREATE/UPDATE - This is the part I had to figure out, and why I asked this question. The Flex first this time:
// FLEX (AS3)
var person:Object = {
PersonID: -1, // -1 for CREATE, actual ID for UPDATE
FirstName: "John",
LastName: "Smith",
BirthDate: "07/19/1983",
CreationDate: "1997-07-16T19:20+01:00" // need W3C DTF for Date WITH Time
};
_pplWebSvcInstance.SavePerson(person); // do the web method call
(For handling those W3C datetimes, see How to parse an ISO formatted date in Flex (AS3)?)
On the .NET web service side then, the trick was figuring out the correct Type on the web method's parameter. If you go with just Object, then step into a call with a debugger, you'll see .NET figures it is a XmlNode[]. Here is what I figured out to do:
[WebMethod]
public int SavePerson(PeopleDataSet p) {
// Now 'p' will be a PeopleDataSet with a Table called 'p' that has our data
// row(s) (just row, in this case) as string columns in random order.
// It WILL NOT WORK to use PeopleDataSet.PersonDataTable as the type for the
// parameter, that will always result in an empty table. That is why the
// LoadFlexDataTable utility method below is necessary.
var adapter = new PersonTableAdapter();
var tbl = new PeopleDataSet.PersonDataTable();
tbl.LoadFlexDataTable(p.Tables[0]); // see below
// the rest of this might be familiar territory for working with DataSets
PeopleDataSet.PersonRow row = tbl.FirstOrDefault();
if (row != null) {
if (row.PersonID > 0) { // doing UPDATE
row.AcceptChanges();
row.SetModified();
}
else { // doing CREATE
row.CreationDate = DateTime.UtcNow; // set defaults here
row.IsDeleted = false;
}
adapter.Update(row); // database call
return row.PersonID;
}
return -1;
}
Now, the kluge utility method you saw called above. I did it as extension method, that is optional:
// for getting the Un-Typed datatable Flex gives us into our Typed DataTable
public static void LoadFlexDataTable(this DataTable tbl, DataTable flexDataTable)
{
tbl.BeginLoadData();
tbl.Load(flexDataTable.CreateDataReader(), LoadOption.OverwriteChanges);
tbl.EndLoadData();
// Probably a bug, but all of the ampersand (&) in string columns will be
// unecessarily escaped (&) - kluge to fix it.
foreach (DataRow row in tbl.Rows)
{
row.SetAdded(); // default to "Added" state for each row
foreach (DataColumn col in tbl.Columns) // fix & to & on string columns
{
if (col.DataType == typeof(String) && !row.IsNull(col))
row[col] = (row[col] as string).Replace("&", "&");
}
}
}
In my particular situation, I have a couple of solutions to my problem. I want to find out which one is more feasible. In this case, I can also achieve my goal by returning a JSON object from my server side code; however, I do not know how it is done and what the best way of doing it is.
First off, I don't need a full aspx page as I only need a response returned from code. So, do I use web services, a handler, or is there any other specific way to do this?
Is this solution feasible? Do I build the JSON string using the StringBuilder class and inject that string into the target aspx page? Are there any precautions or things that I should be aware of?
I appreciate your ideas.
Regards,
Kemal
------------UPDATE !------------
Suppose I have a JSON object in my userlist.aspx page, which then I use with jQuery...
{"menu": {
"id": "color1",
"value": "color",
"popup": {
"menuitem": [
{"value": "Red"},
{"value": "Green"},
{"value": "Yellow"}
]
}
}} // example taken from the json.org/example page
Now when I want to add a new menu items from my aspx page, what do I do... I think this way my question is more specific...
Lets assume I create a new string in my aspx code, as such "{"value": "Blue"}. How do I inject this into the already existing itemlist in the target page? Or is this not the correct approach to this kind of situation? If not, how else can it be achieved?
Also, if I wanted to fire a jQuery event when a new item is added to this list, how is this achieved?
------------UPDATE 2 on 26 August 2015 ------------
By the time I asked this question, the way I was approaching the problem was in another aspect. I am now more proficient in the subject and can gladly accept the most voted answer since the approach to this question clearly should not include the already existing JSON and output a new one from the code as #DavGarcia also suggests.
In your Page_Load you will want to clear out the normal output and write your own, for example:
string json = "{\"name\":\"Joe\"}";
Response.Clear();
Response.ContentType = "application/json; charset=utf-8";
Response.Write(json);
Response.End();
To convert a C# object to JSON you can use a library such as Json.NET.
Instead of getting your .aspx page to output JSON though, consider using a Web Service (asmx) or WCF, both of which can output JSON.
no problem doing it with asp.... it's most natural to do so with MVC, but can be done with standard asp as well.
The MVC framework has all sorts of helper classes for JSON, if you can, I'd suggest sussing in some MVC-love, if not, you can probably easily just get the JSON helper classes used by MVC in and use them in the context of asp.net.
edit:
here's an example of how to return JSON data with MVC. This would be in your controller class. This is out of the box functionality with MVC--when you crate a new MVC project this stuff gets auto-created so it's nothing special. The only thing that I"m doing is returning an actionResult that is JSON. The JSON method I'm calling is a method on the Controller class. This is all very basic, default MVC stuff:
public ActionResult GetData()
{
var data = new { Name="kevin", Age=40 };
return Json(data, JsonRequestBehavior.AllowGet);
}
This return data could be called via JQuery as an ajax call thusly:
$.get("/Reader/GetData/", function(data) { someJavacriptMethodOnData(data); });
With ASP.NET Web Pages you can do this on a single page as a basic GET example (the simplest possible thing that can work.
var json = Json.Encode(new {
orientation = Cache["orientation"],
alerted = Cache["alerted"] as bool?,
since = Cache["since"] as DateTime?
});
Response.Write(json);
If you get code behind, use some like this
MyCustomObject myObject = new MyCustomObject();
myObject.name='try';
//OBJECT -> JSON
var javaScriptSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
string myObjectJson = javaScriptSerializer.Serialize(myObject);
//return JSON
Response.Clear();
Response.ContentType = "application/json; charset=utf-8";
Response.Write(myObjectJson );
Response.End();
So you return a json object serialized with all attributes of MyCustomObject.
I have a requirement to use business objects to call strongly typed table adapters in a three tier model. I also have a requirement to use Telerik reporting, which I didn't see any examples of online. I just see simple examples of creating a simple select to Northwind and connecting the report directly to that. I am using 2008 Q3 of Telerik reporting and my designer doesn't even look the same as the videos I've seen. I have two business objects: boReportHeader and boReportLines and they each have 4 methods that will be passed parameters from the Ui and need to fill the report header and detail section. I spent some time trying to use these from Telerik reporting from both the designer and code-behind and I haven't been successful. I was assuming this would be as straight forward as the RadGrid, but it doesn't appear to be. Anyone have experience with using multiple business object data sources with parameters as a datasource for Telerik Reporting? The main requirement for this project is to generate a PDF file that will be stored in the database as a BLOB file. If this is not possible with Telerik Reporting, does anyone have another tool to suggest other than Telerik Reporting?
Yes You can. See the code below.
namespace TelerikReporting {
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using Telerik.Reporting;
using Telerik.Reporting.Drawing;
public partial class Rep2 : Telerik.Reporting.Report {
public static int GetTotal(int male, int female) {
return (male + female);
}
public Rep2() {
InitializeComponent();
// I am initializing my DataClass.
MyData d = new MyData();
// Adding the DataSource.
this.DataSource = d.GetCityMFCount();
}
}
}
Finally, You call this report in the report Viewer.
protected void Page_Load(object sender, EventArgs e) {
Rep2 rep = new Rep2();
ReportViewer1.Report = rep;
}
Hope this Helps.
Liby George