Ajax Url to Routed WCF in Asp.Net 4 Web Forms - asp.net

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).

Related

ASP.NET ApiController inside a webform can't reach methods

I can't reach any methods from my ApiController in anyway, the routing does appear if i try to reach it by a browser but no methods are shown.
My Controller:
namespace AgroRiego.Controllers
{
public class datacontrol : ApiController
{
[HttpGet, Route("api/get")]
public string Get([FromUri]string user, string pass)
{
string check = SQL.Reader("SELECT * FROM users WHERE username='" + user + "' AND password='" + pass + "'");
if (String.IsNullOrWhiteSpace(check))
{
return "error en credenciales";
}
DataTable horarios = SQL.table_read("SELECT * FROM horario_riego");
string json = Utils.ConvertDataTabletoJSON(horarios);
return json;
}
[HttpPost, Route("api/post")]
public void Post([FromBody]string value)
{
string i = value;
}
}
}
my global asax:
namespace AgroRiego
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
}
and my webapiconfig:
namespace AgroRiego
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// ConfiguraciĆ³n y servicios de API web
// Rutas de API web
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
i have more webforms inside the project (originally it was just html pages with serverside code, but i need to add a couple methods to retrieve and send data, help much appreciated!
EDIT1: i managed to reach HTTP 200 changing the URL but i can't reach the methods anyway (in debug mode it does not stop on the breakpoints) how can i route correctly the Api (so it is not Login.aspx) and how do i fix the methods reaching?
EDIT2: i read in documentation that i need this line in global:
RouteConfig.RegisterRoutes(RouteTable.Routes);
but im not using MVC does that matter? i tried reaching the routes with a brand new MVC Web Api and it yields "No Response"
use a routerprefix with your controller. So you access the URL as
http://localhost/routerprefix/router
HttpClient class can be use to send and receive HTTP requests and responses. Since you are trying to consume a WebApi from a aspx page, better way is to create a HttpClient instance
Below is a very simple implementation. Please check this url for further information
MSDN sample
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("http://localhost:49342/api/get");
if (response.IsSuccessStatusCode)
{
product = await response.Content.ReadAsAsync();
}
By the look of your set up, it seems correct
you have got:
config.MapHttpAttributeRoutes(); - setup the attribute route
config.Routes.MapHttpRoute( - setup the default route
GlobalConfiguration.Configure(WebApiConfig.Register); - to register at startup
so it should work.
I think the problem you are having is the way you are calling it
WebAPI routing work a little different to MVC
for example:
In you get method, the route is set as below
[HttpGet, Route("api/get")]
so you should call it {host}/api/get using a GET http method
in the screen shot, you are calling using {host}/api/get/Get - which would not have work, because no route would match
Same for your POST method
So give it another try and you should be able to reach it
The URL to add in the rest testing tool is
http://localhost:49342/api/get
Method type is GET
If you are calling this web api from aspx page use the httpClient class.

Asp.net web API CORS series/mysterious issue

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.

Execute some code for each request for ASP.NET (aspx and cshtml )

Is there a way to write some code that would be executed for each request to a .aspx or a .cshtml page in asp.net 4.5 apart from using a base page class. it is a very huge project and making changes to all pages to use a base page is a nightmare. Also i am not sure how would this be done for a cshtml page since they don't have a class.
Can we use the Application_BeginRequest and target only the aspx and cshtml files since the website is running in integrated mode.?
basically, i have to check if a user who is accessing the website has a specific ip address against a database and if yes then allow access otherwise redirect.
we are using IIS8 and ASP.Net 4.5 and ASP.Net Razor Web Pages
Also i am not sure how would this be done for a cshtml page since they don't have a class.
You could place a _ViewStart.cshtml file whose contents will get executed on each request.
Alternatively you could write a custom Http Module:
public class MyModule: IHttpModule
{
public void Init(HttpApplication app)
{
app.BeginRequest += new EventHandler(OnBeginRequest);
}
public void Dispose()
{
}
public void OnBeginRequest(object s, EventArgs e)
{
// this code here's gonna get executed on each request
}
}
and then simply register this module in your web.config:
<system.webServer>
<modules>
<add name="MyModule" type="SomeNamespace.MyModule, SomeAssembly" />
</modules>
...
</system.webServer>
or if you are running in Classic Mode:
<system.web>
<httpModules>
<add name="MyModule" type="SomeNamespace.MyModule, SomeAssembly" />
</httpModules>
</system.web>
basically, i have to check if a user who is accessing the website has
a specific ip address against a database and if yes then allow access
otherwise redirect.
Inside the OnBeginRequest method you could get the current user IP:
public void OnBeginRequest(object sender, EventArgs e)
{
var app = sender as HttpApplication;
var request = app.Context.Request;
string ip = request.UserHostAddress;
// do your checks against the database
}
Asp.net MVC filters are especially designed for that purpose.
You would implement ActionFilterAttribute like this (maybe put this new class in a Filters folder in your webapp solution):
public class IpFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string ip = filterContext.HttpContext.Request.UserHostAddress;
if(!testIp(ip))
{
if (true /* You want to use a route name*/)
filterContext.Result = new RedirectToRouteResult("badIpRouteName");
else /* you want an url */
filterContext.Result = new RedirectResult("~/badIpController/badIpAction");
}
base.OnActionExecuting(filterContext);
}
private bool testIp(string inputIp)
{
return true /* do you ip test here */;
}
}
Then you have to decorate any action that would perform the ipcheck with IpFilter like so :
[IpFilter]
public ActionResult AnyActionWhichNeedsGoodIp()
{
/* do stuff */
}

ASP.NET Web Service to call from JS

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.

How to debug UrlRewriter.NET?

I have looked at their help page it seems like I can register a debug logger that outputs information to the 'standard ASP.NET debug window'. My problem is I don't know what that means, if it means the debug output window in Visual Studio (where you see build output, debug output and more) I am not seeing any UrlRewriter debug output.
The rules are working (mostly) I just want to get more debug output to fix issues.
I added the register call to the rewriter section like this:
<rewriter>
<register logger="Intelligencia.UrlRewriter.Logging.DebugLogger, Intelligencia.UrlRewriter" />
....
</rewriter>
I am hosting this website locally in IIS on Vista, to debug it I attach the debugger to the w3wp process.
Other selected parts from the web.config"
<compilation debug="true">
<assemblies>
...
</assemblies>
</compilation>
<trace enabled="true"/>
Where should I see the debug output from UrlRewriter.NET? If it is in the Visual Studio debug output window, any ideas why I am not seeing it there?
Try to run the DebugView for read the messages from Intelligencia.UrlRewriter
Get it from here
http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx
I see the source code, and I belive thats works, but if not works, then why not get the source code, and compile it with your project and just debug it on site ?
I wanted to debug because I had the impression my rewrite rules weren't functioning.
After a while I figured out I had to alter my web.config and add the following line to the 'system.web', 'httpModules' section:
<add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter"/>
For anyone who wants to log the event messages to a file as well as see them in the debug output window, here's a piece of code I created.
Please only use this in a development environment, this code is not optimized.
usage:
In your asp.net application, add a reference to this library (MyPresentationLayer.Web).
Add the following element to 'rewriter' node:
<register logger="IntelligenciaExt.Web.Logging.UrlRewriterIntelligencia.FileLogger, IntelligenciaExt.Web"/>
By default the log file can be found outside your 'www' folder, in the subfolder 'intelligenciaLog'.
using System;
using SysDiag = System.Diagnostics;
using System.IO;
using Intelligencia.UrlRewriter.Logging;
namespace MyPresentationLayer.Web.Logging.UrlRewriterIntelligencia
{
/// <summary>
/// Custom logger for Intelligencia UrlRewriter.net that logs messages
/// to a plain text file (../intelligenciaLog/log.txt).
/// </summary>
public class FileLogger : IRewriteLogger
{
private const string _logFolderName = "../intelligenciaLog";
private const string _logFileName = "log.txt";
private const string _appName = "UrlRewriterIntelligencia.FileLogger";
public FileLogger()
{
LogToFile(Level.Info, "Created new instance of class 'FileLogger'");
}
public void Debug(object message)
{
LogToFile(Level.Debug, (string)message);
}
public void Error(object message, Exception exception)
{
string errorMessage = String.Format("{0} ({1})", message, exception);
LogToFile(Level.Error, errorMessage);
}
public void Error(object message)
{
LogToFile(Level.Error, (string)message);
}
public void Fatal(object message, Exception exception)
{
string fatalMessage = String.Format("{0} ({1})", message, exception);
LogToFile(Level.Fatal, fatalMessage);
}
public void Info(object message)
{
LogToFile(Level.Info, (string)message);
}
public void Warn(object message)
{
LogToFile(Level.Warn, (string)message);
}
private static void LogToFile(Level level, string message)
{
string outputMessage = String.Format("[{0} {1} {2}] {3}", DateTime.Now.ToString("yyyyMMdd HH:mm:ss"),
_appName.PadRight(50, ' '), level.ToString().PadRight(5, ' '),
message);
SysDiag.Debug.WriteLine(outputMessage);
try
{
string pathToLogFolder =Path.Combine(AppDomain.CurrentDomain.BaseDirectory, _logFolderName);
if (!Directory.Exists(pathToLogFolder))
{
Directory.CreateDirectory(pathToLogFolder);
}
string fullPathToLogFile = Path.Combine(pathToLogFolder, _logFileName);
using (StreamWriter w = File.AppendText(fullPathToLogFile))
{
w.WriteLine(outputMessage);
// Update the underlying file.
w.Flush(); // Close the writer and underlying file.
w.Close();
}
}
catch (Exception) { }
}
internal enum Level
{
Warn,
Fatal,
Info,
Error,
Debug
}
}
}

Resources