I am constantly finding a good guide about how to write a web service using .NET with Visual Studio 2010 so I can utilize it with my HTML based website using AJAX.
I know there was a way called the ASMX way but now it's more updated to ServiceHost so what I need is a simple guide which can drive me through how to create asp.net web service using ServiceHost object.
Sorry if it sounds ambiguous or childish.
Place the ScriptManager control on your page and add a reference to your .asmx service:
<asp:ScriptManager ID="myManager" runat="server">
<Services>
<asp:ServiceReference Path="~/MyService.asmx" />
</Services>
</asp:ScriptManager>
In the code-behind of your web-service declare you web method (notice the ScriptService attribute):
namespace MyServices
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[ScriptService]
public class MyService : System.Web.Services.WebService
{
[WebMethod]
public string SayHello(name)
{
return "Hello, " + name;
}
}
}
Now you can consume the web-service from the Javascript like the following:
function queryWebService() {
MyServices.MyService.SayHello('Bobby',
function(result, userContext) {
alert('Web-service response: ' + result);
}, function(result) {
alert('Error!');
});
}
UPDATE
If you want to consume the web-service by simply sending an HTTP GET requests then you can do the following:
Decorate your web-method with a ScriptMethod attribute:
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public string SayHello(name)
{
return "Hello, " + name;
}
Notice the UseHttpGet property which is set to True. You probably also need to modify the web.config file to allow this kind of interaction:
<webServices>
<protocols>
<add name="HttpGet"/>
</protocols>
</webServices>
Now you can make a simple HTTP GET request to your web-service like shown below (the example uses jQuery.ajax):
$.ajax({
url: "/MyService.asmx/SayHello?name=Bobby",
success: function(transport) {
alert('Web-service response: ' + transport.responseText);
}
});
Hope this will help you.
Related
I am facing a CORS policy problem and I do not know how to fix it. I tried many approaches but what makes me crazy is that the service works fine on some devices and I can utilize all its resources and works a little bit on others and does not work at others while the whole devices having the same configuration equally set. To be more clear I am having a Web application based entirely and only on AngularJS 2 and a Web API that exposes a few actions. I installed the IIS and hosted the Web API on the default Web Site, which means it can be called from port 80 for simplicity, and I hosted the Web application using port 4200. Now let's give more detail about my Web API application structure.
EMG.WebApi.Core -> this project is the core project in which I put the controller classes and the web configuration class
EMG.WebApi.WebHost -> this project is used merely for hosting and it contains a reference to the EMG.WebApi.Core project and is the one that contains the Global.asax and within its Application_Start I am calling the Register method of Configuration class of the WebApi.Core and give it as a parameter the GlobalConfiguration object to register my handlers, tracers etc.
using EMG.ElectrometerWS.WebApi.Core;
using System;
using System.Web.Http;
using EMG.ElectrometerWS.WebApi.Core.Configuration;
namespace EMG.ElectrometerWS.WebApi.WebHost
{
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
WebApiConfig.Register(GlobalConfiguration.Configuration);
GlobalConfiguration.Configuration.EnsureInitialized();
}
}
}
using EMG.ElectrometerWS.WebApi.Core.Handlers;
using EMG.ElectrometerWS.WebApi.Core.Tracer;
using System;
using System.Configuration;
using System.Web.Http;
using System.Web.Http.Cors;
using System.Web.Http.Tracing;
namespace EMG.ElectrometerWS.WebApi.Core.Configuration
{
public static class WebApiConfig
{
...
public static string CorsOrigin
{
get
{
string result =
ConfigurationManager.AppSettings.Get("CorsOrigin");
if (!string.IsNullOrEmpty(result))
{
return result;
}
throw new Exception("AppSetting CorsOrigin not found in
web.config file.");
}
}
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
EnableCorsAttribute enableCors =
new EnableCorsAttribute(CorsOrigin, "*", "*");
config.EnableCors(enableCors);
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//config.Routes.MapHttpRoute(
// name: "Secret Api",
// routeTemplate: "secretapi/{controller}/{id}",
// defaults: new { id = RouteParameter.Optional },
// constraints: null,
// handler: new ApiKeyProtectionMessageHandler() {
// InnerHandler = new HttpControllerDispatcher(config)
// });
// Enable ASP.NET Web API tracing
//config.EnableSystemDiagnosticsTracing();
//config.Services.Replace(typeof(ITraceWriter), new
// EntryExitTracer());
//config.Services.Replace(typeof(ITraceWriter), new WebApiTracer());
//config.MessageHandlers.Add(new EmptyPostBodyMessageHandler());
// Message handler to check the performance in production
environment ONLY
config.MessageHandlers.Add(new TracingHandler());
//config.MessageHandlers.Add(new XHttpMethodOverrideHandler());
config.MessageHandlers.Add(new JwtHandler());
}
}
}
EMG.ElectrometerWS.WebApi.WebHost Web.Cofig
<appSettings>
....
<add key="CorsOrigin" value="http://localhost:4200"/>
</appSettings>
What makes me crazy is that everything works fine on my colleague laptop and he can use all the actions. On mine I cannot call some of PUT methods while I can for others on other colleague/testers they can only call GET methods!!! And increases my surprises is that after clearing the browser history/cookies one of those laptops that have only GET methods being called have all things works fine.
What I have tried:
First I added the below code as you can notice above to the configuration class
EnableCorsAttribute enableCors =
new EnableCorsAttribute(CorsOrigin, "*", "*");
config.EnableCors(enableCors);
Creating the following handler and registered it as the first handler before other handlers
public class CorsPreflightHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
request,
CancellationToken cancellationToken)
{
if (request.Headers.Contains("Origin") && request.Method == HttpMethod.Options)
{
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.Headers.Add("Access-Control-Allow-Methods", "*");
return response;
}
return await base.SendAsync(request, cancellationToken);
}
}
Removing the previous code and configured the CORS using the Web.config file of the WebHost project
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http:localhost:4200" />
<add name="Access-Control-Allow-Methods" value="*" />
<add name="Access-Control-Allow-Headers" value="*" />
</customHeaders>
</httpProtocol>
</system.webServer>
Finally removing the web config tags and enabled if on each controller class
[EnableCors(origins: "http://localhost:4200", headers: "*", methods: "*")]
public class XXXController : ApiController
{
Public string Get(int id)
{
return "value";
}
}
The CORS issue seems solved in meantime. I used the first approach by setting an application setting key/value for the allowed Origin then use that key/value to retrieve and register that Origin through a CORS attribute.
<appSettings>
....
<add key="CorsOrigin" value="http://localhost:4200"/>
</appSettings>
public static string CorsOrigin
{
get
{
string result =
ConfigurationManager.AppSettings.Get("CorsOrigin");
if (!string.IsNullOrEmpty(result))
{
return result;
}
throw new Exception("AppSetting CorsOrigin not found in web.config file.");
}
}
public static void Register(HttpConfiguration config)
{
....
EnableCorsAttribute enableCors =
new EnableCorsAttribute(CorsOrigin, "*", "*");
config.EnableCors(enableCors);
}
However, I still do not know what cause the problem from the beginning it may be an IIS issue or missing feature etc.
There is a tabbed panel like HTML in the page, where each tab click will show different data.
Trying to accomplish this with Ajax calls.
In the Visual studio project, I created a web service test.asmx, inside Services folder. So on publish, it is saved at wwwroot/MyApp/Website/Services/test.asmx
asmx.cs
[System.Web.Script.Services.ScriptService]
public class test : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
}
ascx
<asp:ScriptManager ID="_scriptManager" runat="server">
<Services>
<asp:ServiceReference Path="/Services/test.asmx" />
</Services>
</asp:ScriptManager>
<script type="text/javascript">
jQuery(function ($) {
console.log("howdy"); //this does print
var Param1 = 'one';
var Param2 = 'two';
$.ajax({
type: "GET",
url: "/Services/test.asmx/HelloWorld",
data:"",
contentType: "application/json; charset=utf-8",
dataType: "json",
async: "true",
cache: "false",
success: function (msg) {
alert(msg.d);
},
Error: function (x, e) {
alert("errrrr");
}
});
});
</script>
On browsing the page, there is this error in the browser console.
GET http://MyApp/Services/test.asmx/HelloWorld 500 (Internal Server
Error) jQuery.noconflict.js:16
Is this the right way to make the call
Is it because of the prototype.js conflict (not again !!). I already said jQuery(function ($) {..., but still.....
Personally I wouldn't use a web service because I dont think you are going to have the right Sitecore context for doing Sitecore work. I would just use MVC route and use it like an web api.
The controller
using System.Web.Mvc;
using Bonfire.Kickfire.Analytics.Dto;
using Bonfire.Kickfire.Analytics.Models;
namespace Bonfire.Kickfire.Analytics.Controllers
{
public class VisitorController : Controller
{
[HttpGet]
public JsonResult VisitorDetailsJson()
{
var item = Sitecore.Context.Item;
var vi = new VisitorInformation();
var trackerDto2 = vi.GetTrackerDto();
return Json(trackerDto2, JsonRequestBehavior.AllowGet);
}
}
}
The route
using System.Web.Mvc;
using System.Web.Routing;
using Sitecore.Pipelines;
namespace Bonfire.Kickfire.Analytics.Pipelines.Initialize
{
public class InitRoutes : Sitecore.Mvc.Pipelines.Loader.InitializeRoutes
{
public override void Process(PipelineArgs args)
{
RouteTable.Routes.MapRoute(
"Profile", // Route name
"VisitorData", // URL with parameters
new {controller = "Visitor", action = "VisitorDetailsJSON"},
new[] {"Bonfire.Kickfire.Analytics.Controllers"});
}
}
}
The patch file
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<initialize>
<processor type="Bonfire.Kickfire.Analytics.Pipelines.Initialize.InitRoutes, Bonfire.Kickfire.Analytics"
patch:before="processor[#type='Sitecore.Mvc.Pipelines.Loader.InitializeRoutes, Sitecore.Mvc']"/>
</initialize>
</pipelines>
</sitecore>
</configuration>
I implemented Routing in Asp.Net 4 Web App.
With aspx file it works fine, but it doesn't work with WCF.
I have WCF which is called from javascipt file by ajax request.
My WCF code is:
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Signature
{
/// <summary>
/// Get signature info by email address.
/// </summary>
[OperationContract]
[WebInvoke(ResponseFormat = WebMessageFormat.Json)]
public string GetSignatureInfo(string email)
{
...
}
}
}
Web.config:
<services>
<service name="WEB.Services.Signature">
<endpoint address="" behaviorConfiguration="WEB.Services.SignatureAspNetAjaxBehavior"
binding="webHttpBinding" contract="WEB.Services.Signature" />
</service>
</services>
javascript:
var _data = {
"email": self.email.val()
};
$.ajax({
url: '../Signature'
, type: 'POST'
, dataType: 'json'
, data: JSON.stringify(_data)
, success: function (data) {
console.log('success');
}
, error: function () {
console.log('error');
}
});
Global.asax:
void RegisterRoutes(RouteCollection routes)
{
var sr = new ServiceRoute("Signature", new WebServiceHostFactory(), typeof(Signature));
sr.Url = "Services/Signature.svc/GetSignatureInfo";
routes.Add(sr);
}
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
RegisterRoutes(RouteTable.Routes);
}
I get "NetworkError: 404 Not Found - _http://www.my-project.com/Signature". Where am I wrong or what ajax url should be ?!!! Please, help.
Thanks in advance.
My work colleague has found a solution:
The problem was in IIS configuration -
If my app is under Default Site , I should add ajax url with prefix of project. For example, if my Service is located in Web project, I should enter url like : '/Web/Services/MyService/MyFunction' in js file. The same url should be on Global.asax file, in ServiceRoute url, but without first '/'.
In this case, it will work fine locally,but there will be a problem to put it on production server.
The optimal solution:
1. IIS : add web site, configure physical path to him, change its port(!!!).
2. .js + Global.asax : just remove project name from url in both places. So, the url will be like : in js file '/Services/MyService/MyFunction' and in Global.asax 'Services/MyService/MyFunction' (without first '/')
That's all. Big thanks to Miri(colleague).
I am creating an asmx web service.
In visual studio 2012 on the project name I right clicked and added an web service name UserDetails.asmx
Now I am trying to use the web service in the js file. like this
$.ajax({
type: "POST",
url: "UserDetails.asmx/HelloWorld",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
alert('success');
},
error: function () {
alert("Error");
}
});
Its showing error that POST http: //192.168.9.185/GPS/UserDetails.asmx/HelloWorld 500 (Internal Server Error)
Is there any fault in my code or I am missing something so that its showing error.
My Asmx Page
<%# WebService Language="C#" CodeBehind="~/App_Code/UserDetails.cs" Class="UserDetails" %>
My Code Behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
/// <summary>
/// Summary description for UserDetails
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class UserDetails : System.Web.Services.WebService {
public UserDetails () {
//Uncomment the following line if using designed components
//InitializeComponent();
}
[WebMethod]
public string HelloWorld() {
return "Hello World";
}
}
Edit
Short Answer: just uncomment [System.Web.Script.Services.ScriptService]
Digging deep in the error message by using
error: function (xhr,status, error) {
alert("Error");
}
and inspecting xhr revealed that the actual error was something else (Only Web services with a [ScriptService] attribute on the class definition can be called from script).
I used [WebMethod] in my aspx code behind and whenever I received such message, I found out that there was an error in the data I am passing. So try adding data:"{}", in your $.ajax()
as described in this post
When making a read-only request, the empty data parameter is the key. For reasons unknown, jQuery does not properly set the specified content-type when there is no data included.
I am having trouble adding ajax functionality to existing asp.net 4 website.
I have both tried creating webmethod in the aspx page and also tried asmx, but in both cases I get this error Unexpected token <
this is my jQuery:
function postAssets(datapm) {
$.ajax({
type: "POST",
timeout: 20000,
tryCount: 0,
retryLimit: 10,
url: "talk.asmx/HelloWorld",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
console.log('success postAssets '+msg.d);
},
complete: function (jqXHR, status) {
if (status == 'success' || status == 'notmodified') {
console.log('complete postAssets' + jqXHR.responseText);
}
},
error: function (req, status, error) {
console.log('error postAssets');
}
});
}
and this is what is in asmx:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
/// <summary>
/// Summary description for talk
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class talk : System.Web.Services.WebService {
public talk () {
//Uncomment the following line if using designed components
//InitializeComponent();
}
[WebMethod]
public string HelloWorld() {
return "Hello World";
}
}
I wonder if I am missing any webconfig items, or is it all built in in asp.net 4?
<configuration>
<connectionStrings />
<system.web>
<compilation debug="true" targetFramework="4.0" />
<machineKey validationKey="BA5B68AB87AAEA30753960733E796568" decryptionKey="FAF15E4015737A7695D9761" validation="SHA1" />
<authentication mode="Windows" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
</configuration>
Are you returning JSON or markup? Your call to jQuery's ajax() method is expecting JSON but if you're returning markup that starts with a < character then I could imagine it throwing that exception.
I guess the problem is that you declare your Ajax type as POST while in your ASP Controller you declare HelloWorld() as WebMethods. That's why your ajax can't find your HelloWorld Function.
Try to delete this line:
[WebMethods]
and see if that works.