How can I output javascript to a view in asp.net mvc3? - javascript

Good morning All,
I have a javascript variable in my view. I keep doing this...
var skinData = null;
and then on document.ready....
$.ajax({
type: 'POST',
url: 'theme/getskins',
data: {},
contentType: 'application/json; charset=utf-8',
success: function(data){
skinData = data;
}
});
my question is why am I doing this on after the view has loaded. I'm trying to do this in _ViewStart.cshtml
viewPage.ViewBag.SkinInfo = new JsonResult { Data = SkinManager.GetSkins() };
How can I take this value and output its value to my javascript variable. I don't think I need to do another request when I really want to push this to the client on the first trip. Any tips or advice is of course appreciated. How can I do this correctly? I tried a few variations of this but it obvious isn't working. Stuff like...
var skinData = #ViewBag.SkinInfo.Data;
This just outputs the namespace. Any ideas how to do this correctly?
Cheers,
~ck in San Diego

You will want to use some a serializer to convert your .GetSkins() method result into a json object. Either the built in JavaScriptSerializer or json.net
JavaScriptSerializer serializer = new JavaScriptSerializer();
viewPage.ViewBag.SkinInfo = serializer.Serialize(SkinManager.GetSkins());
And then in your view
var skinData = #Html.Raw(ViewBag.SkinInfo);

Here's a way of doing it using a Html helper. It will convert your object into json and put it into a javascript variable.
HtmlHelper extension method
public static MvcHtmlString Jsonize(this HtmlHelper helper, string variableName, object obj)
{
StringBuilder str = new StringBuilder();
str.Append("<script type='text/javascript'>");
str.Append("var ");
str.Append(variableName);
str.Append("=");
if (obj == null)
str.Append("null");
else
str.Append(JsonHelper.Serialize(obj));
str.Append(";");
str.Append("</script>");
return MvcHtmlString.Create(str.ToString());
}
The json serializer. I'm using the DataContractJsonSerializer in this case.
public class JsonHelper
{
public static string Serialize(object obj)
{
string json = null;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
json = Encoding.Default.GetString(ms.ToArray());
}
return json;
}
}
Once you have that done, you can just use it in your views to create a javascript variable that contains your object
#Html.Jsonize("data", ViewBag.SkinInfo.Data);
which will create something like this:
<script type='text/javascript'>
var data = { your serialized object };
</script>

Related

Return JavaScript object literal, not JSON string, from ASP.NET MVC endpoint

For various reasons, I have switched from ASP.NET MVC's built in JSON serializer (the one that returns a System.Web.Mvc.JsonResult object (see edit below)) to Newtonsoft. I didn't realize until after I began testing that the former returns a JavaScript object literal, while Newtonsoft returns a JSON formatted string.
I like not having to parse JSON strings on the client side — having it already as an object literal is very convenient — but I want to stick with Newtonsoft for other technical reasons.
For example, instead of seeing this result on my client...
"{"Errors":["Please enter a valid email address."],"HasErrors":true}"
...I'd like to see this result:
{"Errors":["Please enter a valid email address."],"HasErrors":true} // no quotes
Is there a way to make Newtonsoft return JS object literals instead of strings?
EDIT
The way my question was framed wasn't the best. There's nothing wrong with the JsonResult type. In fact, the solution still uses it. The only problem was the default Controller.Json methods, which can be overridden to use Newtonsoft (Json.NET) instead of the built-in serializer.
Just write a custom JsonResult that uses Newtonsoft serializer:
Something along the lines:
public abstract class BaseController : Controller
{
protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding)
{
return new JsonNetResult
{
ContentType = contentType,
ContentEncoding = contentEncoding,
Data = data
};
}
protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding, JsonRequestBehavior behavior)
{
return new JsonNetResult
{
ContentType = contentType,
ContentEncoding = contentEncoding,
Data = data,
JsonRequestBehavior = behavior
};
}
}
JsonNetResult.cs:
using System;
using System.Web;
using System.Web.Mvc;
using Newtonsoft.Json;
public class JsonNetResult : JsonResult
{
public JsonSerializerSettings SerializerSettings { get; set; }
public Formatting Formatting { get; set; }
public JsonNetResult()
{
Formatting = Formatting.None;
SerializerSettings = new JsonSerializerSettings();
JsonRequestBehavior = JsonRequestBehavior.DenyGet;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
if (JsonRequestBehavior == JsonRequestBehavior.DenyGet
&& String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.");
}
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = !string.IsNullOrEmpty(ContentType)
? ContentType
: "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
if (Data != null)
{
var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
var serializer = JsonSerializer.Create(SerializerSettings);
serializer.Serialize(writer, Data);
writer.Flush();
}
}
}
Credit: https://gist.github.com/jpoehls/1424538
Answer is here: How to force ASP.NET Web API to always return JSON?
Excerpt:
Clear all formatters and add Json formatter back.
GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());
EDIT
I added it to Global.asax inside Application_Start().

Passing XMLDocument to Stored Procedure

My current setup is as follows:
Client Javascript JSON stringified object is passed to a server function as so
Client:
var requestObject = JSON.stringify(clientObject);
$.ajax({
url: 'ServerClass.aspx/ServerFunction',
data: requestObject,
dataType: "json",
contentType: "application/json; charset=utf-8",
cache: false,
context: document.body,
type: 'POST',
success: saveSuccessfulFunction
});
Server:
[WebMethod(EnableSession = true)]
public static int SaveAllReportOptions(string requestObject)
{
XmlDocument xdoc = JsonConvert.DeserializeXmlNode("{\"root\":" + clientObject + "}", "roots");
DBClass.Save(xdoc);
}
public int Save(XmlDocument clientObject)
{
SqlCommand dCmd = new SqlCommand("MyStoredProcedure", conn);
dCmd.CommandType = CommandType.StoredProcedure;
dCmd.Parameters.AddWithValue("#objectXML", SqlDbType.Xml).Value = clientObject.InnerXml;
SqlParameter returnValue = dCmd.Parameters.Add("#ret", SqlDbType.Int);
returnValue.Direction = ParameterDirection.ReturnValue;
conn.Open();
dCmd.ExecuteNonQuery();
conn.Close();
int i = Convert.ToInt32(dCmd.Parameters["#ret"].Value);
return i;
}
The stored procedure successfully extracts the different nodes/attributes from the XMLDocument passed in and goes on to perform the relevant update/insert commands.
SELECT tab.col.value('att1[1]','NCHAR(10)') as attribute1,
tab.col.value('att2[1]','INT') as attribute2...
FROM #objectXML.nodes('/roots/root') AS tab(col)
My issue isn't with the above code but with certain do's and don'ts observed from various online/in house software coding standards.
Source 1
X DO NOT use XmlNode or XmlDocument to represent XML data. Favor using instances of IXPathNavigable, XmlReader,XmlWriter, or subtypes of XNode instead. XmlNode and XmlDocument are not designed for exposing in public APIs.
Source 2
✓ DO use XmlReader, IXPathNavigable, or subtypes of XNode as input or output of members that accept or return XML.
Use these abstractions instead of XmlDocument, XmlNode, or XPathDocument, because this decouples the methods from specific implementations of an in-memory XML document and allows them to work with virtual XML data sources that expose XNode, XmlReader, or XPathNavigator.
Source 3
X DO NOT subclass XmlDocument if you want to create a type representing an XML view of an underlying object model or data source.
Basically, I would like to know if it is safe and reliable enough to use XMLDocument for the purpose detailed above. And if not, if there are any alternatives which would be better suited for my scenario.
I used this approach -
For e.g. You have customer object with multiple orders ( child classes)
1. At client side - after assigning values in both the classes
customerObject = JSON.stringify(cls_m_Customer, function(k, v){ return v === "" ? "" : v });
2. At server side -
JavaScriptSerializer jss = new JavaScriptSerializer();
cls_m_Customer objCustomer = new cls_m_Customer();
objCustomer = jss.Deserialize<cls_m_Customer>(customerData);
3. At Business Class - create two dictionaries for customer and orders classes and add these tables to dataset and then convert ds into xml like -
Dictionary<string, cls_m_Customer> dic_Customer = new Dictionary<string, cls_m_Customer>();
dic_Customer.Add("1", this);
DataSet ds = new DataSet();
DataTable dtCustomer = DictionaryToDataTable.ConvertTo<cls_m_Customer>(dic_Customer, "Customer");
DataTable dtOrders = DictionaryToDataTable.ConvertTo<cls_m_Order>(this._Order, "Orders");
ds.Tables.Add(dtCustomer);
ds.Tables.Add(dtOrders);
DataRelation drQ = new DataRelation("Customer Related Orders", dtCustomer.Columns["_CustomerID"], dtOrders.Columns["_CustomerID"]);
drQ.Nested = true;
ds.Relations.Add(drQ);
customerXml = ds.GetXml();

asp.net mvc, returning multiple views as JSON

Is it possible to return 2 separate views to an ajax call in Asp.net?
for example, if foo1 and foo2 are 2 ActionResult methods each returning a view?
return Json(new { a = foo1(), b = foo2() });
currently attempting this, the end result is that javascript gets it back as a class object rather then the actual view, anybody know how to get the resulting rendered html instead?
EDIT: I guess what I'm actually going for, is there a way for me to return the rendered view in string format?
Yes their is a way of returning view in string format.
For this you need to do following things:
1.You need some method in which you can pass your viewname along with object model. For this please refer below code and add to your helper class.
public static class RenderViewLib
{
public static string RenderPartialView(this Controller controller, string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = controller.ControllerContext.RouteData.GetRequiredString("action");
controller.ViewData.Model = model;
using (var sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
}
The above code will return your view in string format.
2.Now call above method from your json call like this:
[HttpPost]
public JsonResult GetData()
{
Mymodel model = new Mymodel();
JsonResult jr = null;
jr = Json(new
{
ViewHtml = this.RenderPartialView("_ViewName", model),
ViewHtml2 = this.RenderPartialView("_ViewName2", model),
IsSuccess = true
}, JsonRequestBehavior.AllowGet);
return jr;
}
and you will get your view as string format from your json call.
Hope this is what you are looking for.

How to populate javascript variable with JSON from ViewBag?

I have this Index action:
public ActionResult Index()
{
var repo = (YammerClient) TempData["Repo"];
var msgCol = repo.GetMessages();
ViewBag.User = repo.GetUserInfo();
return View(msgCol.messages);
}
GetMessages returns a list of POCO messages and GetUserInfo returns a POCO with the info of the user (id, name, etc).
I want to fill a javascript variable with the JSON representation of the user info.
So I would want to do something like this in the view:
...
<script>
var userInfo = "#ViewBag.User.ToJson()"
</script>
...
I know that doesn't work, but is there a way to do that? I want to avoid having to do an ajax request once the page is loaded just to get the user info.
In View you can do something like this
#{
var jss = new System.Web.Script.Serialization.JavaScriptSerializer();
var userInfoJson = jss.Serialize(ViewBag.User);
}
in javascript you can use it as
<script>
//use Json.parse to convert string to Json
var userInfo = JSON.parse('#Html.Raw(userInfoJson)');
</script>
Was using this solution for simple objects. But I had some problems getting an array to js objects so I'll just leave what I did here.
C#
#{
using Newtonsoft.Json;
ViewBag.AvailableToday = JsonConvert.SerializeObject(list);
}
js
var availableToday = JSON.parse('#Html.Raw(ViewBag.AvailableToday)');
Client-Side Code:
This is an ajax call to a .Net MVC Controller:
var clientStuff;
$.ajax({
type: 'GET',
url: '#Url.Action("GetStuff", "ControllerName")',
data: {},
dataType: "json",
cache: false,
async: false,
success: function (data) {
clientStuff = data;
},
error: function(errorMsg) {
alert(errorMsg);
}
});
Server-Side Code:
CONTROLLER:
public JsonResult GetStuff()
{
return Json(_manager.GetStuff(), JsonRequestBehavior.AllowGet);
}
MANAGER:
public IEnumerable<StuffViewModel> GetStuff()
{
return _unitofWork.GetStuff();
}
UNIT OF WORK:
public IEnumerable<StuffViewModel> GetStuff()
{
var ds = context.Database.SqlQuery<StuffViewModel>("[dbo].[GetStuff]");
return ds;
}
Unit of Work can be a query to a sproc (as I have done), a repository context, linq, etc.
I'm just calling a sproc here for simplicity, although it could be argued that the simplicity lies with Entity Framework and Linq.
You can change this line :
ViewBag.User = repo.GetUserInfo();
To
ViewBag.User = new HtmlString(repo.GetUserInfo());
You should add using Microsoft.AspNetCore.Html; or using System.Web; if HtmlString is not accessible.

MVC 3 jquery ajax post 2 objects

I have a controller action that takes two objects as arguments. I can't get it to work at all they always come back as null. My latest try looks like below. I have tried many other variations. In this case the FormInfo class is a class with 2 properties that are types for Form1 and Form2. I have also tried having the controller take in the two classes as arguments and the data part looked like { form1: form1Data, form2: form2Data } that was not working as well. I also tried using JSON.stringify to form the data with no luck.
Looking in the network monitor I see the data going back to the server it's just the engine that MVC uses to decode the query string to the objects can't handle what I'm passing back.
Thanks in advance for any information!
ClientSide
var formData = $("#form1").serialize();
var formData2 = $("#form2").serialize();
var formInfo = new Object();
formInfo.FormData = formData;
formInfo.FormData2 = formData2;
$.ajax({
url: 'Controller/Action',
type: 'POST',
data: formInfo,
success: function (data) {
//do stuff
}
});
ServerSide
public ActionResult SaveForms(FormInfo formInfo)
{
//Do Stuff here
}
You could use the a JSON request in conjunction with the .serializeArray() jQuery method. Let's suppose that you have the following model:
public class FormInfo
{
public Form1Data Form1Data { get; set; }
public Form2Data Form2Data { get; set; }
}
where Form1Data and Form2Data are some completely arbitrary complex classes. Now on the client we suppose that you have 2 distinct forms (#form1 and #form2 whose input element names match your complex structures in terms of default model binder wire format). Sending an AJAX request and packing the 2 forms together becomes trivial:
var form1Data = {};
$.each($('#form1').serializeArray(), function () {
form1Data[this.name] = this.value;
});
var form2Data = {};
$.each($('#form2').serializeArray(), function () {
form2Data[this.name] = this.value;
});
$.ajax({
url: '#Url.Action("someaction", "somecontroller")',
type: 'post',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({
form1Data: form1Data,
form2Data: form2Data
}),
success: function (result) {
// TODO: do something with the result
}
});
And of course the controller action you are POSTing to looks like this:
[HttpPost]
public ActionResult SomeAction(FormInfo formInfo)
{
...
}
I am doing something like this but i have a object and other Formdata to pass my Controller
var discrepancy = self.newCptyReply();
if ($('#UploadFile')[0]) {
var upload = new FormData(),
file = $('#UploadFile')[0].files[0];
upload.append('id', self.globalMessageId());
upload.append('discrepancy', ko.toJSON(discrepancy));
upload.append('doc', file);
}
datacontext.saveCptyToReply(self, upload);
And in controller signature
public ActionResult SaveCptyToReply(Guid id, Trade discrepancy, HttpPostedFileBase doc)
But when it reaches Controller id , doc are ok but discrepancy is null... It has data when funciton is called..
What to do...

Categories

Resources