I have a method on a page marked with the webmethod and scriptmethod tags..
The method returns a collection of objects to a jquery function as JSON data with no hassles and without me having to manually serialize it.
I am now trying to recreate that same method using a HTTPHandler and was wondering why i have to now manually serialize the data.
What makes the webmethod different?
Because an HTTP handler (kind of) sits above the ASP WebForms Stack, you are totally responsible for the workings and output of the handler.
You can utilise (almost) anything you can get your hands on within the .NET framework, but for sure, an HTTPHandler will be more work than an off-the-shelf solution provided by ASP.NET.
The ASP.NET page handler is only one
type of handler. ASP.NET comes with
several other built-in handlers such
as the Web service handler for .asmx
files.
You can create custom HTTP handlers
when you want special handling that
you can identify using file name
extensions in your application
See http://msdn.microsoft.com/en-us/library/ms227675(VS.85).aspx
Web method provides you a connection between your c# class and Js file. Nowadays Using Json is a best way to get the return message in a smart format for a js function or anywhere in js file.
Regards
For lesser work:
Move your method to an ASMX (Web Service):
You will benefit the built-in serialization provided by the ScriptService:
namespace WS{
[System.web.Script.Services.ScriptService()]
[System.Web.Services.WebService(Namespace:="http://tempuri.org/")]
public class WebService1 : System.Web.Services.WebService
{
[WebMethod]
public Person GetDummyPerson()
{
Person p = new Person();
p.Name = "John Wayne";
p.Age = 20;
}
[WebMethod]
public IList GetPersonsByAge(int age)
{
//do actual data retrieval
List result = new List();
result.add(new Person());
result.add(new Person());
return result;
}
}
class Person
{
String Name;
int Age;
}
}
On the client side:
WS.GetDummyPerson(function(p){
alert(p.Name + "-->" + p.Age);
});
WS.GetPersonsByAge(10,function(list){
for(var i=0;i<list.length;i++)
{
document.write(list[i].Name + "==>" + list[i].Age);
}
});
Related
I was wondering if it's possible to use an extension method with asp.net webforms and nvelocity. I would like to set some defaults if the string value is null or empty.
Example of .vm file:
Example of my email body...
Billable Status: $billableStatus.Evaluate()
rest of my email body...
Attempted extension method:
public static class Helper
{
public static string Evaluate(this string value)
{
if (String.IsNullOrEmpty(value))
return "Not Provided";
else
return value;
}
}
Or is there an alternative to what I'm tryting to accomplish?
I don't think NVelocity can resolve extension methods with C#/VB.NET syntax sugar. What I do is register an instance of a helper in the velocity context:
var context = VelocityContext();
context.Put("helper", new Helper());
context.Put("billableStatus", "something");
...
and then in your template:
$helper.Evaluate($billableStatus)
You have to make your helper non-static for this to work, of course.
I came across something similar in past and I was looking for something more sophisticated and with more control. I found that NVelocity does provide a way to intercept the method and property calls but for that you will have to implement certain things. In order to make your custom interceptor you will need to implement NVelocity.IDuck. For example
public class MyClass : NVelocity.IDuck
{
public object GetInvoke(string propName)
{
....
}
public object Invoke(string method, params object[] args)
{
....
}
public void SetInvoke(string propName, object value)
{
....
}
}
Now any instance of MyClass will intercept and pass the method and property calls to our these three function implementation and give us a chance to resolve and return the output. You may notice from these three function signatures that in order to implement them we may need some reflection where we can locate respective methods on available extension types and execute them. If needed you can read following blog post for more details about going this way. NVelocity and extension methods
ASP.NET MVC 2.0 will now, by default, throw an exception when an action attempts to return JSON in response to a GET request. I know this can be overridden on a method by method basis by using JsonRequestBehavior.AllowGet, but is it possible to set on a controller or higher basis (possibly the web.config)?
Update: Per Levi's comment, this is what I ended up using-
protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding)
{
return Json(data, contentType, JsonRequestBehavior.AllowGet);
}
This, like other MVC-specific settings, is not settable via Web.config. But you have two options:
Override the Controller.Json(object, string, Encoding) overload to call Json(object, string, Encoding, JsonRequestBehavior), passing JsonRequestBehavior.AllowGet as the last argument. If you want this to apply to all controllers, then do this inside an abstract base controller class, then have all your controllers subclass that abstract class.
Make an extension method MyJson(this Controller, ...) which creates a JsonResult and sets the appropriate properties, then call it from your controller via this.MyJson(...).
There's another option. Use Action Filters.
Create a new ActionFilterAttribute, apply it to your controller or a specific action (depending on your needs). This should suffice:
public class JsonRequestBehaviorAttribute : ActionFilterAttribute
{
private JsonRequestBehavior Behavior { get; set; }
public JsonRequestBehaviorAttribute()
{
Behavior = JsonRequestBehavior.AllowGet;
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
var result = filterContext.Result as JsonResult;
if (result != null)
{
result.JsonRequestBehavior = Behavior;
}
}
}
Then apply it like this:
[JsonRequestBehavior]
public class Upload2Controller : Controller
MVC 2 block Json for GET requests for security reasons. If you want to override that behavior, check out the overload for Json that accepts a JsonRequestBehavior parameter.
public ActionResult Index()
{
return Json(data, JsonRequestBehavior.AllowGet)
}
I also got this error when I first use MVC 2.0 using my old code in MVC 1.0. I use fiddler to identify the cause of the error. See the steps on how to troubleshoot it using Fidder -
http://www.rodcerrada.com/post/2011/07/11/jQuery-getJSON()-does-not-tirgger-the-callback-in-ASPNET-MVC-2.aspx
Is this is the security issue MVC2 was trying to address?
http://haacked.com/archive/2009/06/25/json-hijacking.aspx
If so, it seems like the vulnerability is only an issue if you are trying to do a json call to an outside website. If your MVC2 app is only making json calls to your own website (to fill jqgrids for example), shouldn't you be able to safely override the Json call in your base controller to always allow get?
Just change JSON code from :
$.getJson("methodname/" + ID, null, function (data, textStatus)
to:
$.post("methodname/" + ID, null, function (data, textStatus)
I am implementing a dynamic ASMX web service via a custom HttpHandler, and my web service has recently stopped generating WSDL automatically. When I use ?WSDL on the asmx url, I get the following error:
System.InvalidOperationException: XML Web service description was not found.
at System.Web.Services.Protocols.DiscoveryServerProtocol.WriteReturns(Object[] returnValues, Stream outputStream)
at System.Web.Services.Protocols.WebServiceHandler.WriteReturns(Object[] returnValues)
at System.Web.Services.Protocols.WebServiceHandler.Invoke()
This worked fine a while ago, so I'm wondering if there's a file permission problem somewhere.
A Google search does not return any reference to this particular situation.
I doubt that my code is relevant to the problem; it has not changed:
[WebService(Description = "...", Namespace = "...")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
public class MyWebService : System.Web.Services.WebService
{
[WebMethod]
void MyWebMethod() {}
}
public class VirtualWebServiceFactory : IHttpHandlerFactory
{
public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
WebServiceHandlerFactory wshf = new WebServiceHandlerFactory();
MethodInfo coreGetHandler = wshf.GetType().GetMethod("CoreGetHandler", BindingFlags.NonPublic | BindingFlags.Instance);
IHttpHandler handler = (IHttpHandler)coreGetHandler.Invoke(wshf, new object[] { typeof(MyWebService), context, context.Request, context.Response });
return handler;
}
}
Decompiling System.Web.Services.Protocols.DiscoveryServerProtocol.WriteReturns() reveals that it looks up the XML service description in a dictionary created somewhere else.
I was hoping that someone familiar with the DiscoverServerProtocol etc. might know under what circumstances the XML service description might fail to be built.
The following works just fine:
ServiceDescriptionReflector reflector = new ServiceDescriptionReflector();
reflector.Reflect(typeof(MyWebService), "...");
Navigating to MyWebService.asmx shows all the functions and allows testing them. But using ?WSDL gives the exception above.
Just for fun, try making your WebMethod public.
However, the real answer is to not screw around with .NET Framework code that's not meant to be called. What's wrong with just calling GetHandler? What are you trying to accomplish here that can't be accomplished without messing around in the internals of an obscure class?
Hmm, after many months, found out that the URL was being re-written to include other parameters than the ?WSDL, which made the private function choke.
I'm trying to use the official jQuery autocomplete plugin with an ASMX web service in an ASP.NET 3.5 Web Forms application. If I understand it correctly, the autocomplete plugin can only use HTTP GET to call a service (with two query string parameters: q and limit). I figured out how to make the web service respond to the HTTP GET calls, but I cannot figure out how to make it return JSON data (even though the service returns JSON data when I call it using jQuery $.ajax with type='POST', when called from the autocomplete plugin it always returns XML). Here are some code snippets:
Web service:
[ScriptService]
[WebService(Namespace = "http://tempuri.org/")]
public class UserWS: WebService
{
[WebMethod]
[ScriptMethod(UseHttpGet=true, ResponseFormat=ResponseFormat.Json)]
public List<UserDisplayInfo> GetUsers
(
string q,
int limit
)
{
List<UserDisplayInfo>users = GetUsers(q, limit);
return users.ToList();
}
}
Web page:
$("#test").autocomplete(
"./Services/UserWS.asmx/GetUsers",
{
dataType: 'json',
type: 'POST', // this setting is ignored
contentType: 'application/json;charset=utf-8',
parse: function(data)
{
//...
}
});
If this is not possible I wonder what would be a better alternative:
fixing autocomplete plugin to use HTTP POST and JSON data instead of GET and query string parameters;
using a different autocomplete plugin (I looked at a few, but at this point the official plugin has most recommendations, and I'm not sure if other plugins support HTTP POST);
an alternative to ASMX web service, such as WCF web service (I would not want to use WCF because ASMX web service is simpler to implement -- no web.config changes, no contracts, no interfaces -- and it gives me everything I need);
something else.
I found several similar questions at StackOverflow, but I did not find the answer that would work for me. Any (good) ideas?
Autocomplete plugin wants results in plain text format, not JSON. Each item should be on a separate line:
foo\n
bar\n
baz\n
Try replacing web service with generic handler (.ashx):
public class MyHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write("foo\nbar\nbaz");
}
public bool IsReusable
{
get { return false; }
}
}
On the side note you can't use GET if you want ASMX web service to return JSON. See How to let an ASMX file output JSON.
What is the best practice to support data for asp.net 2.0-3.5 ajax web application?
I don't want to use update panels, just plain text data (JSON).
Should I use web services? Or is there another way.
Errrr... Use an .aspx page ? What are handlers for ?
You just have to create a generic base handler that will take care of json (de)serialization (e.g. using Json.net) and then implement handlers for your ajax calls.
public abstract class JsonHandlerBase<TInput, TOutput> : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "application/json";
TInput input = (TInput)context.Request; // Desesialize input
TOutput output = ProcessRequest(context, parameter);
string json = (string)output; // Serialize output
context.Response.Write(json);
}
public abstract TOutput ProcessRequest(HttpContext context, TInput input);
public bool IsReusable { get { return false; } }
}
This is just an example, it's up to you to decide want you need in your base handler.
You can use plain aspx pages or handlers and just output JSON. You do this by erasing all the Html in the aspx and then using Response.Write() in the code.
Then for the front end JS you can use JQuery or any other Ajax framework.
You may also want to check out Asp.Net MVC. MVC has a JsonResult resonse type and is very easy to use together with JQuery to get very good Ajax functionality.