serializing a json response using web service - asp.net

As I'm new to knockout, web services and all this things, I'm trying to populate a dropdownlist using knockout js and a web service.
the Html code is
<body>
<select data-bind="options: printers"></select>
</body>
and the javascript block is
<script>
$(document).ready(function () {
var viewModel = {
printer: ko.observable(),
printers: ko.observableArray()
}
$.ajax({
type: "POST",
contentType: "application/json",
url: "PapersDDLs.asmx/getPrinters1",
data: "{}",
dataType: "json",
success: function (response) {
viewModel.printers(response.d);
}
});
ko.applyBindings(viewModel);
});
</script>
the web service I call is
Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.Collections
Imports System.Collections.Generic
Imports System.Collections.Specialized
Imports System.Web.Script.Serialization
<System.Web.Script.Services.ScriptService()> _
<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class PapersDDLs
Inherits System.Web.Services.WebService
<WebMethod()> _
Public Function getPrinters1() As String
Dim db As New DataClassesDataContext
Dim printers = From p In db.Printers Select p
Dim values As New List(Of PrinterItem)
For Each pr In printers
values.Add(New PrinterItem(pr.BrandModelName, pr.Id.ToString()))
Next
db.Dispose()
Return New JavaScriptSerializer().Serialize(values)
End Function
End Class
The problem is that the string that is returned is made character by character.
Any help will be valuable
Thanks!

The function in your web service is slightly incorrect. You don't need to do the Javascript serialization yourself. Because you have marked the web service as a System.Web.Script.Services.ScriptService, the content of the response will automatically be serialized as JSON.
The method signature should be:
Public Function getPrinters1() As List(Of PrinterItem)
and the return statement should be:
Return values

Related

ASP.NET - WebMethod not getting called when using Class, jsonerror

I am trying to pass an object to a WebMethod which takes parameters as a class.
If I pass the parameters separately, it works, but not as a class. What am I missing?
My ajax call:
var obj = {Id: 1234};
var item = JSON.stringify(obj);
$.ajax({
url: 'InventoryItems.aspx/Update',
data: item,
type: 'POST',
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function () {
console.log("in success");
}
})
WebMethod:
The version that works:
<WebMethod(EnableSession:=True)>
Public Shared Function Update(Id As string) As String
Dim res As String = ""
Return res
End Function
WebMethod:
The version that does not work:
<WebMethod(EnableSession:=True)>
Public Shared Function Update(item As Item) As String
Dim res As String = ""
Return res
End Function
The class Item:
Public Class Item
Public Property Id As String = String.Empty
End Class
I get a 500 error in Google Chrome dev tool. So, in gist, the WebMethod does not get hit if I put a breakpoint there. If I use just the Id as the parameter in the WebMethod, it gets hit. My original object has about 20 properties, so I would like to pass an object with 20 fields rather than passing 20 parameters separately.
Am I missing anything? Any reference or settings?
Thank you for helping me in advance.
The problem on my end is FriendlyUrls.
There's probably a better way to do this, but I excluded it from the project in the bin folder; and commented-out references to it in RouteConfig.cs and ViewSwitcher.ascx. (You may have others.)
This was just for testing, but the problems I was having are gone on this page. I also have a script manager on my test-page, and the script manager and bundling are commented-out on the master page, but now I'm not convinced that that's an issue.
I guess the ASP.NET AJAX proxy class PageMethods looks for a complete url to find the code-behind method and bombs without it.
When you are using input parameter as integer, its working fine as your JSON is compliant with the parameter
For parameter as an object, use following
{ "item": { "Id": "1234" } }
If the underlying Id property is a number, remove the corresponding quotes on 1234.
Note that the parameter name are case sensitive and hence "item" should have i in lower case and "Id" has in upper case.
You follow the convention of :-
Opening and closing braces marks the boundary of field
Variable name has to be 1st ('item' in this case)
Variable value follows after a colon (an object with property "Id' and its corresponding value
2) & 3) gets repeated for the whole hierarchy of the concerned object.
The following worked for me:
The ajax call:
var obj = {Id: 1234};
var item = JSON.stringify(obj);
$.ajax({
url: 'InventoryItems.aspx/Update',
data: JSON.stringify({item:item}),
type: 'POST',
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function () {
console.log("in success");
}
})
<WebMethod(EnableSession:=True)>
Public Shared Function Update(item As string) As String
Dim res As String = ""
Return res
End Function
And then in that WebMethod, I could do something like:
Dim jss As New JavaScriptSerializer()
Dim itemDetails As Item = jss.Deserialize(Of Item)(item)
dim id as string = itemDetails.Id

allow webservice to be called from script

hi there i have a demo page in my web site, i am learning how to call webservice from script
this is my page
http://applicazioni.vsc300.it/Mediweb2015/Prova.aspx
$(document).ready(function () {
var params = { 'IDPaziente': 6586 }
$.ajax({
"dataType": 'json',
"contentType": "application/json; charset=utf-8",
"type": "GET", "url":"http://applicazioni.vsc300.it/Service.asmx/CercaPaziente",
"data": params,
"success": function (msg) {
var json = jQuery.parseJSON(msg.d);
//valorizza texbox
$("#TXT_CognomePaziente").val(json.Denominazione);
},
error: function (xhr, textStatus, error) {
alert(error);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input name="TXT_CognomePaziente" type="text" id="TXT_CognomePaziente" name="TXT_CognomePaziente" />
and this is the service:
' To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
<System.Web.Script.Services.ScriptService()> _
<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class Service
Inherits System.Web.Services.WebService
' <WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest, Method = "GET")>
<WebMethod()> _
<ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
Public Function CercaPaziente(IDPaziente As Integer) As String
Dim serialiser As JavaScriptSerializer = New JavaScriptSerializer()
Dim Paz As New CLS_Paziente
Paz.GetCercaAnagrafica(IDPaziente)
Dim serializer As JavaScriptSerializer = New JavaScriptSerializer()
Dim serializedItems As String = serializer.Serialize(Paz)
Return serializedItems
End Function
End Class
it returns an error, that Only Web services with a [ScriptService] attribute on the class definition can be called from script.
but i enabled it!!!
what can i do?
From this doc:
If more than one attribute is applied to a single program element, the attributes are enclosed in a single set of angle brackets and delimited from one another by a comma. For example:
<Obsolete(), WebMethod()>
Public Function PageCount(strURL As String) As Integer
(This was hard to find, by the way. I couldn't find it anywhere on MSDN.) So, this isn't what your code does, and the .NET compiler is probably ignoring your attributes altogether. Try this and see if it works:
<System.Web.Script.Services.ScriptService(), _
WebService(Namespace:="http://tempuri.org/"), _
WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1), _
Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Public Class Service
Inherits System.Web.Services.WebService

Can't receive JSON array being posted to me by third party

The format I am receiving is:
[{"item1": "value1","item2": "value2"},{"item1": "value2","item2": "value4"}]
The main issue seems to be that no matter what I try I receive the error "Type System.Collections.Generic.IDictionary'2 Is Not supported for deserialization of an array."
Scouring the internet only comes up with my needing to wrap the array in a top level variable (ie. the array cannot be on the root level). Unfortunately I am unable to change what and how I am receiving the data.
Here is all my code with the things I have attempted commented out:
My test ajax used to simulate what the third party will be sending to me:
Head of "test.html":
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<SCRIPT type="text/javascript">
<!--
function testPost() {
var theData;
theData = '[{"item1": "value1","item2": "value2"},{"item1": "value2","item2": "value4"}]';
//theData = '{"item1": "value1","item2": "value2"}'; //I can make a single array element work, but that is not what I will receive
$.ajax({
type: "POST",
contentType: "application/json",
url: "test2.aspx/test_array",
data: theData,
dataType: "json",
success: function(msg) {
alert(msg);
}
});
}
//-->
</SCRIPT>
Body of "test.html"
<input type="submit" value="test Post" onClick="testPost();" /><br>
Test.aspx.vb in it's entirety:
Imports System.Collections.Generic
Imports System.Web.Script.Serialization
Partial Class test2
Inherits System.Web.UI.Page
' Public Shared Function test_array(ByVal item1 As String, ByVal item2 As String) As String ' works if I am passing a single array element
' Public Shared Function test_array(ByVal theobj As Object) As String ' "Type System.Collections.Generic.IDictionary`2 Is Not supported for deserialization of an array."
' Public Shared Function test_array(ByVal theobj As List(Of Object)) As String' "Type System.Collections.Generic.IDictionary`2 Is Not supported for deserialization of an array."
' Public Shared Function test_array(ByVal theobj As Test_Request) As String ' "Type System.Collections.Generic.IDictionary`2 Is Not supported for deserialization of an array."
' Public Shared Function test_array(ByVal theobj As List(Of Test_Request)) As String' "Type System.Collections.Generic.IDictionary`2 Is Not supported for deserialization of an array."
' Public Shared Function test_array(ByVal theobj As Dictionary(Of String, String)) As String' "Type System.Collections.Generic.IDictionary`2 Is Not supported for deserialization of an array."
<System.Web.Services.WebMethod> _
Public Shared Function test_array(ByVal d As List(Of Test_Request)) As String
Return "test"
End Function
End Class
The "Test_Request" class:
Public Class Test_Request
Property item1 As String
Get
Return m_item1
End Get
Set(value As String)
m_item1 = value
End Set
End Property
Private m_item1 As String
Property item2 As String
Get
Return m_item2
End Get
Set(value As String)
m_item2 = value
End Set
End Property
Private m_item2 As String
End Class
Please let me know if I failed to include any needed data. I have been going in circles for a few days now and before deciding to post here I attempted to recreate all my failed attempts in this test mock up. Hopefully there is simply something I am overlooking.
It seems to me that you are trying to deserialize an array of dictionary objects. I would do something like as follows.
On the server side:
<HttpPost>
<Route("test")>
Public Function test(data As YourArray) As String
Return "done"
End Function
-----------
Public Class YourArray
Inherits List(Of YourDictionaryObject )
End Class
Public Class YourDictionaryObject
Inherits Dictionary(Of String, String)
End Class
I just tested and I can confirm that the following does work:
function doTest() {
var theData = [];
theData.push({
item1: "value1",
item2: "value2"
});
theData.push({
item1: "value3",
item2: "value4"
});
$.ajax({
type: "POST",
contentType: "application/json",
url: "somewhere/test",
data: JSON.stringify(theData),
dataType: "json",
success: function(msg) {
alert(msg);
}
});
}
I checked and the Request Payload looks like this:
[{"item1":"value1","item2":"value2"},{"item1":"value3","item2":"value4"}]
This gets deserialized on the server side as YourArray. By the way, I am using Asp.net Web Api (not WCF where serializing/deserializing dictionaries can be tricky).
Your poco is wrong. Item1 and Item2 need to be string arrays
Public Class RootObject
Public Property item1() As String
Public Property item2() As String
End Class

My jQuery ajax doesn't work

Just started to learn jQuery ajax today, followed what tutorial said but it did not work.
HelloWorld is the method name, but it seems not be recognized as a method name but a page name based on the error message.
jQuery
$(document).ready(function () {
//alert("hello world");
$('.ordernumber').on('click', function () {
var orderNum = $(this).text();
$.ajax({
type: "POST",
url: "./OrderDetail.asmx/HelloWorld",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
alert(msg);
// Do interesting things here.
}
});
//alert($(this).text());
});
});
OrderDetail.asmx.vb
Imports System
Imports System.Web.Services
Public Class OrderDetail
Inherits System.Web.Services.WebService
<WebMethod()> _
Public Function HelloWorld() As String
Return "Hello World"
End Function
End Class
Error Message:
POST http://localhost:64616/OrderDetail.asmx/HelloWorld 500 (Internal Server Error)
I think you need to add <System.Web.Script.Services.ScriptService()> to your class;
<System.Web.Script.Services.ScriptService()> _
Public Class OrderDetails
Inherits System.Web.Services.WebService
'' rest of your code
End Class
Also to return Json you need to decorate your methods with;
<ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
Update
When creating a fresh ASMX Web Service, the default code states;
' To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
' <System.Web.Script.Services.ScriptService()> _
You are expecting a JSON back, but an asmx webservice returns a XML instead you need to add
<WebMethod()> _
<ScriptMethod(ResponseFormat:=ResponseFormat.Json)>_
Public Function HelloWorld() As String
Return "Hello World"
End Function
The link for more explanaiton

How to use Fine Uploader server-side in a non-MVC ASP.NET application

I have the following Fine Uploader code in markup in an aspx page in ASP.NET (not MVC) project:
<link href="../js/fineuploader/fineuploader-3.5.0.css" rel="stylesheet">
<script type="text/javascript" src="../js/fineuploader/fineuploader-3.5.0.js"></script>
<script type="text/javascript">
$(document).ready(function () {
var uploader = new qq.FineUploader({
element: $('#fine-uploader')[0],
request: { /* <-- THIS IS WHAT I NEED TO FIGURE OUT */
endpoint: 'server/handleUploads'
},
autoUpload: true,
multiple: false,
text: {
uploadButton: '<asp:Button ID="fineUploadButton" runat="server" CssClass="button" style="width:6;5" Text="Browse" />'
},
validation: {
allowedExtensions: ['mp3', 'wav']
}
});
});
</script>
For the client side piece, this works fine. I've modified the fineuploader.css to get the exact look I want (mostly). With the client side piece being done I just need to handle this in my code-behind by handling the request endpoint piece.
I've viewed several examples on the github page, but for ASP there are no non-MVC examples. Even the simplest of these examples involve creating a new class and inheriting from the Controller class. Since I'm not doing this site with MVC, how can I handle the server side aspect of this?
My client side piece is pretty much complete, and I can supply more info on my server side code and organization if necessary.
Handling the requests sent by Fine Uploader is fairly trivial. All upload requests, by default, are multipart encoded POST requests. By default, all parameters are also present in the request payload as form fields.
I am not an ASP.NET developer, but it shouldn't be too difficult to handle MPE requests in ASP.NET. In fact, this is fairly trivial in most server-side languages. Here's an example of some code that should handle such a request:
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
public class UploadController : ApiController
{
public async Task<HttpResponseMessage> PostFormData()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
try
{
// Read the form data.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the file names.
foreach (MultipartFileData file in provider.FileData)
{
Trace.WriteLine(file.Headers.ContentDisposition.FileName);
Trace.WriteLine("Server file path: " + file.LocalFileName);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
}
Note that your server-side code must also return a valid JSON response. This is described more in Fine Uploader's server-side readme. There is an article on MSDN that describes dealing with JSON in .NET apps. Perhaps the JsonConvert class is required here.
You can read more about handling these requests at http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2.
Kmarks2, it might be too late for you but this could help others.
To handle it server side in ASP.NET (not MVC) a WebHandler can be created. It is the Generic handler item with .ashx extension (e.g. FileUpload.ashx ).
The handler looks like this:
<%# WebHandler Language="C#" Class="FileUpload" %>
using System;
using System.Web;
using System.IO;
public class FileUpload : IHttpHandler {
public void ProcessRequest (HttpContext context)
{
// Handle files sent from client
}
public bool IsReusable {
get {
return false;
}
}
}
The endpoint should look like:
'http:// your server name/xxx/FileUpload.ashx'
( e.g.'http://localhost:3293/xxx/FileUpload.ashx')
Working with ASP.NET which is not an MVC project a WebHandler is needed for handling request seamlessly.
For examples and usage of WebHandler see here.
With reference to SanthoshM's answer and inline with the combination of Fine Uploader MVC VB.net Server-Side sample, this is what i came up with. I hope this may be helpful to someone.
Client Side
<script>
var existingHandler1 = window.onload;
window.document.body.onload = function () {
var galleryUploader = new qq.FineUploader({
element: document.getElementById("fine-uploader-gallery"),
template: 'qq-template-gallery',
request: {
endpoint: '../App_Extension/FileUpload.ashx'
},
debug: true,
thumbnails: {
placeholders: {
waitingPath: '../App_Images/waiting-generic.png',
notAvailablePath: '../App_Images/not_available-generic.png'
}
},
validation: {
allowedExtensions: ['jpeg', 'jpg', 'gif', 'png'],
sizeLimit: 3145728 // 3 MB = 3 * 1024 * 1024 bytes
},
retry: {
enableAuto: true
},
});
if (existingHandler1) { existingHandler1() }
}
</script>
Server Side
<%# WebHandler Language="VB" Class="FileUpload" %>
Imports System
Imports System.Web
Imports System.IO
Imports System.Linq
Imports System.Drawing
Public Class FileUpload : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/plain"
'context.Response.Write("Hello World")
Dim reader As StreamReader = New StreamReader(context.Request.InputStream)
Try
Dim values As String = DateTime.Now.Millisecond.ToString + Rnd(10000).ToString + ".jpg" 'reader.ReadToEnd()
' 'BLL.WriteLog(values)
'Dim img As System.Drawing.Image = System.Drawing.Image.FromStream(context.Request.InputStream)
' img.Save("C:\DownloadedFiles\" + DateAndTime.TimeString + ".Jpeg", System.Drawing.Imaging.ImageFormat.Jpeg)
''BLL.WriteLog(values)
Dim responseText As String = Upload(values, context)
'BLL.WriteLog(responseText)
context.Response.Write(responseText)
'context.Response.Write("{""error"":""An Error Occured""}")
Catch ex As Exception
'BLL.WriteLog(ex.Message + ex.StackTrace)
End Try
End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
Function Upload(ByVal uploadFile As String, ByVal context As HttpContext) As String
'BLL.WriteLog("1")
On Error GoTo upload_error
Dim strm As Stream = context.Request.InputStream
Dim br As BinaryReader = New BinaryReader(strm)
Dim fileContents() As Byte = {}
Const ChunkSize As Integer = 1024 * 1024
'Dim uploadFile As String
'BLL.WriteLog("2")
' We need to hand IE a little bit differently...
' If context.Request.Browser.Browser = "IE" Then
'BLL.WriteLog("3")
Dim myfiles As System.Web.HttpFileCollection = System.Web.HttpContext.Current.Request.Files
Dim postedFile As System.Web.HttpPostedFile = myfiles(0)
If Not postedFile.FileName.Equals("") Then
Dim fn As String = System.IO.Path.GetFileName(postedFile.FileName)
br = New BinaryReader(postedFile.InputStream)
uploadFile = fn
End If
'End If
'BLL.WriteLog("4")
' Nor have the binary reader on the IE file input Stream. Back to normal...
Do While br.BaseStream.Position < br.BaseStream.Length - 1
'BLL.WriteLog("5")
Dim b(ChunkSize - 1) As Byte
Dim ReadLen As Integer = br.Read(b, 0, ChunkSize)
Dim dummy() As Byte = fileContents.Concat(b).ToArray()
fileContents = dummy
dummy = Nothing
Loop
'BLL.WriteLog("6")
' You now have all the bytes from the uploaded file in 'FileContents'
' You could write it to a database:
'Dim con As SqlConnection
'Dim connectionString As String = ""
'Dim cmd As SqlCommand
'connectionString = "Data Source=DEV\SQLEXPRESS;Initial Catalog=myDatabase;Trusted_Connection=True;"
'con = New SqlConnection(connectionString)
'cmd = New SqlCommand("INSERT INTO blobs VALUES(#filename,#filecontents)", con)
'cmd.Parameters.Add("#filename", SqlDbType.VarChar).Value = uploadFile
'cmd.Parameters.Add("#filecontents", SqlDbType.VarBinary).Value = fileContents
'con.Open()
'cmd.ExecuteNonQuery()
'con.Close()
' Or write it to the filesystem:
Dim writeStream As FileStream = New FileStream("C:\DownloadedFiles\" & uploadFile, FileMode.Create)
'BLL.WriteLog("7")
Dim bw As New BinaryWriter(writeStream)
bw.Write(fileContents)
bw.Close()
'BLL.WriteLog("8")
' it all worked ok so send back SUCCESS is true!
Return "{""success"":true}"
Exit Function
upload_error:
Return "{""error"":""An Error Occured""}"
End Function
End Class

Resources