ServiceReference a self hosted WCF service - asp.net

I am currently maintaining and developing a website which uses a lot of webservices in an ajax way.
Registering of the services is done in the aspx like this:
<asp:ScriptManagerProxy id="ScriptManager1" runat="server">
<services>
<asp:ServiceReference Path="WebServices/WSAdministrator.asmx"></asp:ServiceReference>
</services>
</asp:ScriptManagerProxy>
and consuming the services in the javascript is done like this
WSAdministrator.GetConsumerClubInfo(ConsumerClubId,
OnSucceededToGetConsumerClubInfo,
OnFailedToGetConsumerClubInfo);
I want to know if I can reference a self-hosted WCF service(on the same machine) this easily.
any suggestions?
EDIT: The WCF service is running on a windows service, it exposes both webHttpBinding and basicHttpBinding endpoints.
After Reading ASP.Net WCF Service with no App_Code , I realized that I should just create an svc file which will act as a reference to the service.
I created this svc file:
<%# ServiceHost Language="C#" Service="MyService.Namespace.Contract" %>
and in the web.config file I added these lines:
<services>
<service name="MyService.Namespace.Contract">
<endpoint address="setAddress" binding="basicHttpBinding" contract="MyService.Namespace.ContractInterface"/>
</service>
</services>
The address is working, but when I try to access the reference from the svc, I get the following error:
The type '', provided as the Service attribute value in the
ServiceHost directive could not be found.
What am I missing here?
Note: There have been some nice answers, but all to things I already know, my question is about how to reference my Self Hosted WCF service using asp.net so that I can use it from javascript, that's all, and for that I still have no answers...
I saw some replies to similar questions telling there should be an IIS hosted service acting as a "pipe" to the actual service, and then the ScriptManager should reference it, Maybe that's the only answer...

When you are self hosting your WCF Service you do not use .SVC file, but create the service host in your windows service's OnStart method in the following way.
WebServiceHost myServiceHost = null;
if (myServiceHost != null)
{
myServiceHost.Close();
}
myServiceHost = new WebServiceHost(typeof(YourClassName));
myServiceHost.Open();
If you want to host your service to support WebHttpBinding then the hosting class should be WebServiceHost and if you want to host wsHttpBinding or any other you should use ServiceHost.
Once service starts running clients can connect to it.
The following link contains step by step process for doing it.
If you have to support RESTful service that is able to talk to using AJAX and Jquery then you should go with WebServiceHost and you would decorate your operation contracts in the following way.
[ServiceContract()]
public interface IMyInterface
{
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "GetArray",
BodyStyle = WebMessageBodyStyle.Bare)]
MyArray[] GetArray();
}
You can find some info on this even in the following question.

Of course you can and it would look like this with WCF,
<asp:ServiceReference Path="~/WSAdministrator.svc" />
See Here and here for some examples.

Related

WCF request doesn't flow via asp.net pipeline

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.

How to force soap header authentication for my scenario?

The problem is: I need to connect to a soap web service; generated by java code; using ASP.Net client via C# through MS Visual Studio 2013.
Try 1, The usual way:
I have added a web service reference using the wsdl and by assigning the credentials like:
Credentials.Username.Username = "test";
Credentials.Password.Password = "test";
When executing, the following exception is being encountered:
The login information is missing!
Try 2:
I have searched for similar problems like:
how-to-go-from-wsdl-soap-request-envelope-in-c-sharp
Dynamic-Proxy-Creation-Using-C-Emit
c# - Client to send SOAP request and received response
I had chosen to generate a proxy class using the wsdl tool, then added the
header attribute, but I have found the following note from Microsoft:
Note: If the Web service defines the member variables representing the SOAP headers of type SoapHeader or SoapUnknownHeader instead of a class deriving from SoapHeader, a proxy class will not have any information about that SOAP header.
Try 3:
I have tried to change the service model in the client web.config:
<bindings>
<basicHttpBinding>
<binding name="CallingCardServicePortBinding">
<security mode="TransportWithMessageCredential" >
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
Then added the credentials like the first try, but the following error appears:
MustUnderstand headers:[{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security] are not understood
So, now I don't know what to do !
I have no control over the web service and I need to build a client that understands it.
Help Please!
The Soap Request template is the following:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="...">
<soapenv:Header>
<credentials>
<userName>someUserName</userName>
<password>somePassword</password>
</credentials>
</soapenv:Header>
<soapenv:Body>
<ser:someRequest>
.......
.......
.......
</ser:someRequest>
If the destination web service uses authentication, then just ASMX won't do, since it is not aware of authentication, encryption etc. You have 2 options:
Use Microsoft WSE: http://www.microsoft.com/en-us/download/details.aspx?id=14089
this is nothing but an extension of ASMX which makes it Security/Encryption aware. (and some other features) technically, you'll be adding a reference to the WSE DLL and your Soap Proxy will extend from the WSE SOAP Client instead of the System one.
once you do that, the proxy class will have additional username/password properties that you can use to authenticate properly.
set the properties and see the outgoing request using fiddler. if the header is not what you want (because of namespaces etc.), then you can write a custom outgoing message inspector and modify the soap request nicely.
The other option (preferred) is to use WCF.
ASMX and WSE are older than WCF. WCF tries to bring all the web service nuances under one roof. if you get a WCF service reference, it (svcutil.exe) will automatically create the proxy class and the right bindings for you. (mostly custom)
once you do that, try setting the user name and password.
if that doesn't work, (i have frequently struggled to generate the right soap header for remote java based services that require username/password authentication), you can define a static header chunk in the web.config/app.config, that'll be sent as part of every request.
e.g.
<client>
<endpoint>
<headers>
<credentials>
<userName>someUserName</userName>
<password>somePassword</password>
</credentials>
</headers>
</endpoint>
</client>

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

Call WCF Service Through Javascript, AJAX, or JQuery

I created a number of standard WCF Services (Service Contract and Host (svc) are in separate assemblies). I fired up a Web Site in IIS to host the Services (i.e., address is http://services:1000/wcfservices.svc).
Then in my Web Site project I added the reference. I am able to call the services normally. I am needed to call some of the services client side. Not sure if I should be looking at articles calling WCF services through AJAX, JQuery, or JSON enabled WCF Services. Can anyone provide any thoughts or experience with configuring as such?
Some of the changes I made was adding the following to the Operation Contract:
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "SetFoo")]
void SetFoo(string Id);
Then this above the implementation of the interface:
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
Then in the service webconfig I have this (parens are angle brackets):
<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
<baseAddressPrefixFilters>
<add prefix="http://services:1000/wcfservices.svc/"/>>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
<serviceHostingEnvironment multipleSiteBindingsEnabled="false" />
Then in the client side I attempted this:
<asp:ScriptManagerProxy ID="ScriptManagerProxy1" runat="server">
<compositeScript>
<Scripts>
<asp:ScriptReference
Path="http://Flixsit:1000/FlixsitWebServices.svc" />
</Scripts>
</CompositeScript>
</asp:ScriptManagerProxy>
I am attempting to call the service like this in javascript:
wcfservices.SetFoo(string Id);
Nothing is working. If it is idea or a better solution to call JSON enable, JQuery, etc....I am willing to make any changes.
Thanks for any suggestions/tips provided....
The same origin policy will prevent the client from making AJAX calls to a service located in a different domain (different host) than the one serving up the web page. You can make this work using JSONP rather than JSON. You'll need to change your service to accept a callback function and deliver to the client a bit of javascript invoking this callback with the JSON data.

Resources