WCF request doesn't flow via asp.net pipeline - asp.net

I have a WCF service hosted in an asp.net application.
Here's the service (shortened):
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceContract(Name = Name, Namespace = Namespace)]
[ServiceBehavior(Name = Name, Namespace = Namespace)]
public class WcfMaintenanceFacade {...}
Here's hosting:
RouteTable.Routes.Add(new ServiceRoute("entity/maintenance/5.20", new ServiceHostFactory(), typeof(WcfMaintenanceFacade)));
And here's relevant config section:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
</system.serviceModel>
My service instantiates, the requests are coming in, and event HttpContext.Current is not empty.
There are two (major, for me) issues that I can't solve:
HttpContext.Current.Session is empty
Global.asax's Application_BeginRequest is never called
And yes, from the call stack it seems like the request is going through WCF activation pipeline, not ASP.net pipeline. So what am I doing wrong?

About the session, you handle it with OperationContext.Current.RequestContext instead of HttpContext.Current.Session.
HttpContext: Current is always null when accessed from within a WCF
service. Use
T:System.ServiceModel.OperationContext.Current.RequestContext instead.
Read more here: https://msdn.microsoft.com/en-us/library/aa702682.aspx
Application_BeginRequest are used by ASP.Net applications, but WCF works different from common web applications, thus BeginRequest could not be hit on each request.
The ASP.NET HTTP runtime handles ASP.NET requests but does not
participate in the processing of requests destined for WCF services
.... he WCF Service Model intercepts messages addressed to WCF
services and routes them through the WCF transport/channel stack
So, your problem can be related to this issue. This information is also available at the same link.
Hope it helps with your questions.

And the answer is simple (and, well, obvious):
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
Yes. RAMMFAR.

For me it is clear that these two technologies are not supposed to be working in the same application, and that's why they have two different pipelines. Service by the nature is an isolated thing. Now you just try to find a workaround, relying on the fact they both work on same IIS.
I would recommend you rather start from the goals, from what you want to achieve. If you need new service-like functionality integrated into native ASP.NET application you can
1) use ASMX services (will give you SAOP if you need it) and/or page methods
2) try to integrate WEB API in case you need JSON service.

Related

Forms Authentication Cookie and WCF

I have an asp.net 4.0 application (client) that makes ajax/json calls to a http facade that then passes on the calls to our wcf service layer.
Users must authenticate on the client using forms authentication. The idea then being that the authentication cookie will be passed to and be accessible at the http facade. [Design based on Dino Esposito's book - Microsoft ASP.NET and AJAX: Architecting Web Applications]
The problem is, that at the facade, HttpContext.Current.User.Identity.Name is an empty string and IsAuthenticated is false.
I have enabled compatibility by adding the following to my system.ServiceModel section in my web.config (http facade level):
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
I have decorated my service with the following:
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Required)]
When I am debugging in the ajax/facade app I can see that cookies exist at HttpContext.Current.Request.Cookies. It appears that Anonymous is being used and not my authenticated user.
Both applications are running on the same IIS server.
Calls to the AJAX enabled wcf service are made via serviceProxy.js. Perhaps this method is not passing the necessary cookie?
WCF tracing is currently showing '..ASPXANONYMOUS=.....; ASP.NET_SessionId=....; .ASPXAUTH=.....' in the message log.
I get the feeling I am missing something simple but am too close to the problem.
Any suggestions welcomed.
I am not sure I completely understand the context of what you are trying to accomplish, but if these are two separate applications you are going to need to share machine keys in order to decrypt/encrypt the auth cookies in both.
in your web.config, make sure you have the following set:
<machineKey
validationKey="[generated key]"
validation="HMACSHA512"
decryptionKey="[generated key]"
decryption="AES"
/>
see how to generate these keys (and more info about them) on this codeproject article:
ASP.Net machineKey Generator - CodeProject
Let me know if this helps...

WCF AND ASP.NET session sharing

Here is my case, I am working on an infrastructure for a scale able application.
I am creating a simple ASP.NET client page that consumes a WCF service with an AJAX call (simple xmlhttp object not .net script manager).
I need the 2 to share sessions, so I have instructed the ASP.NET client application to store the session in SQL with the aspnet_regsql.exe tool.
I have checked that WCF service is receiving the same session ID that the ASP.NET client produces, but in the service the session keys container is empty.
I am under an impression that it might have something to do with the app name in the configuration, but I really don't know...
Any direction ?
If you must share ASP.NET session with WCF services, you need to check out WCF Services and ASP.NET on MSDN to find out how to enable the WCF ASP.NET compatibility mode.
Mostly, it boils down to:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
in your WCF service's service-side config. Also, you must make sure your WCF service implementation doesn't explicitly deny the ASP.NET compatibility mode.
So your WCF service class must either allow or even require the ASP.NET compatibility:
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class YourService : IYourService
or
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class YourService : IYourService
I have found the answer to my problem.
I needed to change the "TempGetAppID" procedure in the SQL ASPState DB created with the "aspnet_regsql.exe" tool to take the APP_NAME() and not the passed argument.
That made sure that all application now share the same session.
once I have made the change the WCF Service has started to be aware of sessions inserted in my asp.net application.
problem solved.
ALTER PROCEDURE [dbo].[TempGetAppID]
#appName tAppName,
#appId int OUTPUT
AS
SET #appName = APP_NAME()
SET #appId = NULL
SELECT #appId = AppId
FROM [ASPState].dbo.ASPStateTempApplications
WHERE AppName = #appName

Access Session in WCF service from WebHttpBinding

I'm using WCF service (via WebGet attribute).
I'm trying to access Session from WCF service, but HttpContext.Current is null
I added AspNetCompatibilityRequirements and edited web.config but I still cannot access session.
Is it possible to use WebGet and Session together?
Thank you!
Yes, it is possible. If you edit the web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
and add the AspNetCompatiblityRequirements, the HttpContext.Current should be available.
Check everything once again, maybe you've put the attribute in the wrong place (the interface instead of the class?).
A RESTfull service with a session?
See excellent discussion here: Can you help me understand this? "Common REST Mistakes: Sessions are irrelevant"
http://javadialog.blogspot.co.uk/2009/06/common-rest-mistakes.html (point 6)
and
http://www.peej.co.uk/articles/no-sessions.html
Quote from Paul Prescod:
Sessions are irrelevant.
There should be no need for a client to "login" or "start a connection." HTTP authentication is done
automatically on every message. Client applications are consumers of
resources, not services. Therefore there is nothing to log in to!
Let's say that you are booking a flight on a REST web service. You
don't create a new "session" connection to the service. Rather you ask
the "itinerary creator object" to create you a new itinerary. You can
start filling in the blanks but then get some totally different
component elsewhere on the web to fill in some other blanks. There is
no session so there is no problem of migrating session state between
clients. There is also no issue of "session affinity" in the server
(though there are still load balancing issues to continue).

How do I Resolve an application URL from a background thread in ASP.NET MVC?

The app splits off into two threads; the main web app and a secondary thread used for asynchronous event handling. The secondary thread receives an event where it needs to send an email with a fully qualified URL of the main app (plus additional route arguments) inside it.
Eg. http://Server.com/App/RouteData?AdditionalArguments
Of course the background thread does not have the luxury of using HttpContext.Current to resolve a Url, because there's no request. No HttpRequest, no HttpContext...
I discovered that most of the methods ASP.NET (even with MVC) uses to build URLs rely on HttpContext. Does there exist a way to build a fully qualified application URL in ASP.NET without using HttpContext or any of it's derivatives?
I'm looking for a thread-safe method like:
UrlHelper.GetApplicationtUrl()
Any Ideas? Your suggestions are much appreciated.
I had this exact problem. I ended up storing the url in the web.config file. I did mine like so:
<appSettings>
<!-- Urls -->
<add key="AppDomain" value="http://localhost:1273/" />
<add key="ConfirmUrl" value="http://localhost:1273/Auth/Confirm/?code={0}" />
</appSettings>
and called it like this in the service layer:
string confirmUrl = string.Format(ConfigurationManager.AppSettings["ConfirmUrl"], confirmCode);
If you can't just use the configuration file, when creating the Thread, use the ThreadStart delegate to provide the base information you need to the new thread.

Possible to invoke ASMX service with parameter via url query string?

I've got a asmx service that takes a single int parameter. I can open the URL to the service and see the service description screen. From here I can enter the query parameters into a form and invoke the web service.
Is there any way to invoke a web service directly from a URL/query string?
This doesnt work:
http://localhost:4653/MyService.asmx?op=MyWebMethod&intParameter=1
Any ideas? I'd really like to be able to do this from a standard link due to some deployment issues. Am I going to have to wrap the request in a normal aspx page?
You can decorate your method to allow HTTP GET requests, which should in turn do what you're looking for like so:
[WebMethod]
[ScriptMethod(UseHttpGet=true)]
public string MyNiftyMethod(int myint)
{
// ... code here
}
And edit the web.config :
<system.web>
<webServices>
<protocols>
<add name="HttpGet"/>
</protocols>
Then you'll be able to call this method like so:
http://mysite.com/Service.asmx/MyNiftyMethod?myint=12345
EDIT: Note that this method of performing GET requests does come with some security risks. According to the MSDN documentation for UseHttpGet:
Setting the UseHttpGet property to
true might pose a security risk for
your application if you are working
with sensitive data or transactions.
In GET requests, the message is
encoded by the browser into the URL
and is therefore an easier target for
tampering.
ASMX web services use SOAP. SOAP requests use only POST to invoke methods. You will need to generate a proxy client in your aspx page to invoke the web service. If you really need to use GET verbs to invoke web services you might need to use a different approach such as WCF REST.

Resources