I created a WCF Data Service inside a Windows Service and tried to access the HttpContext.
I added this to my config file:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
However, when I try to access it, it is null.
protected override void OnStartProcessingRequest(ProcessRequestArgs args)
{
base.OnStartProcessingRequest(args);
HttpContext httpContext = HttpContext.Current;
File.AppendAllText(#"c:\Temp\ERROR.log",
httpContext != null
?"HTTPCONTEXT IS NOT NULL"
:"HTTPCONTEXT IS NULL");
}
What else should I set?
I found the answer, I'm afraid so:
The disabled ASP.NET HTTP features are:
HttpContext.Current: This is always null in this mode. For ASMX services, this is a ThreadStatic property that is stored in the Thread Local Store (TLS). WCF provides a counterpart to this feature: OperationContext.Current.
Source: http://blogs.msdn.com/b/wenlong/archive/2006/01/23/516041.aspx
Related
We have developed an ASP Net MVC application using the Repository pattern.
We are creating a db context instance by using a context provider class like:
public class ContextProvider
public static DBEntities GetContext()
{
return HttpContext.Current.Items["_EntityContext"] as DBEntities;
}
}
Here we are making sure that the DBEntities db call exists only during the existence of the request - we are putting an instance into a Session map - HttpContext.Current.Items["_EntityContext"] in this example.
We are using this in our entire Asp Net Mvc Project as following:
public class TeamRepository
{
#region Members
private DBEntities storeDB = null;
#endregion Members
#region Constructors
public TeamRepository()
{
storeDB = ContextProvider.GetContext();
}
#endregion Constructors
#region Methods
...
Now we need to create a WCF service to enable access to some features to other vendors.
Since all the Repository classes are a part of a project - they were not excluded to a separated DLL I made a reference to the entire project in my new WCF project so that I could use already existing DB Repository method calls.
Here I am facing an issue since I am not able to access to the Session variable HttpContext.Current.Items["_EntityContext"] - method call public static DBEntities GetContext() is always returning null when called from WCF Service.
I tried to make HttpContext.Current Available Within a WCF Service available by placing
[ServiceBehavior(AddressFilterMode=AddressFilterMode.Any)]
[AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Required)]
on my Service class,
and tweaking the serviceHostingEnvironment section of web.config, which now looks like this:
<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
<baseAddressPrefixFilters>
<add prefix="http://localhost” />
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
but with no results.
I am using Windows 10.
Do you know a way I can access HttpContext.Current.Items["_EntityContext"]... contained within Asp Net Mvc project from my WCF Project?
Regards
The issue is resolved using the following steps:
I decorated my service implementation with the AspNetCompatibilityRequirements attribute:
[AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Required)]
public class Service : IService {
. . .
}
The last thing I had to do was necessitated by WCF not supporting multiple host headers; I had to hard-wire the WCF endpoint to listen on a specific hostname. In this case, this involved tweaking the serviceHostingEnvironment section of web.config, which now looks like this:
<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
<baseAddressPrefixFilters>
<add prefix=http://services.mydomain.com” />
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
And then adding another attribute to the service implementation class and initializing the HttpContext.Current.Items session:
[ServiceBehavior(AddressFilterMode=AddressFilterMode.Any)]
[AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Required)]
public class Service : IService {
HttpContext.Current.Items["_EntityContext"] = new DBEntities();
...
}
I built a WCF service library and hosted it through a host application. Then I constructed a client application, but it seems that the address of the service host is hard coded in the client program. What if the host changes its address? Is it possible to write the client application so that the address of the host can be entered by the client at run time?
Yes, it's possible, if you write the WCF client proxy by hand, instead of generating it automatically with Visual Studio adding a service reference.
Let's start from this example (https://learn.microsoft.com/it-it/dotnet/framework/wcf/feature-details/how-to-use-the-channelfactory), just to understand how ChannelFactory works, and then modify it a little bit, adding the following function.
private ChannelFactory<IMath> _myChannelFactory;
// ...
private IMath GetChannel(string endpointConfigurationName, string endpointAddress)
{
if (_myChannelFactory == null)
{
this.DebugLog("Channel factory is null, creating new one");
if (String.IsNullOrEmpty(endpointAddress))
{
_myChannelFactory = new ChannelFactory<IMath>(endpointConfigurationName);
}
else
{
_myChannelFactory = new ChannelFactory<IMath>(endpointConfigurationName, new EndpointAddress(endpointAddress));
}
}
return _myChannelFactory.CreateChannel();
}
You can define the default server IP in the client App.config file
<system.serviceModel>
<!-- ... -->
<client>
<endpoint address="net.tcp://192.168.10.55:81/math/" binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_IMath"
contract="MyNamespace.IMath" name="NetTcpBinding_IMath" />
</client>
</system.serviceModel>
In this way, when GetChannel("NetTcpBinding_IMath", "net.tcp://127.0.0.1:81/math") is called, it picks up the endpoint configuration from App.config file, replacing the default address (192.168.10.55) with the new one (127.0.0.1).
Some more documentation about ChannelFactory: https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.channelfactory-1.createchannel?view=netframework-4.8
Preamble: in our app we have some logic based on custom message inspector. It parses WCF messages and set data (session or cookies) in current Http context over HttpContext.Current.
Situation: after switching to async WCF calls, we lost access to current context, which is null by now. I'm understanding that context actually saved and thread destroyed while await does his job, but maybe there's a way to fix this with less blood and without dangerous techniques?
Upd: here are some code. Sync ver:
public ActionResult Task()
{
//some logic
var result = ourService.DoCall();
//some logic
}
//in WCF message inspector
public void AfterReceiveReply(ref Message reply, object correlationState)
{
var request = HttpContext.Current; //got context here
}
Async ver:
public async Task<ActionResult> Task()
{
//some logic
var result = await ourService.DoCallAsync();
//some logic
}
//in WCF message inspector
public void AfterReceiveReply(ref Message reply, object correlationState)
{
var request = HttpContext.Current; //got null
}
A little note on WCF, when hosting the WCF service running within an ASP.NET site, you need to enable aspnetCompatability mode, this can be done in the Wen.config
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
Or individualy on the service level using
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class CalculatorService : ICalculatorSession
{//Implement calculator service methods.}
You can check on the specifics from the Microsoft page, this should give you more information about the mode.Enabling it will let WCF run under the ASP.NET pipeline instead of creating Modules to hook up to the events of the pipeline, this will also let you access the HttpContext object that is otherwise null if the setting is not enabled
A qoute from the referened article :
HttpContext: Current is always null when accessed from within a WCF
service. Use RequestContext instead.
The value of the RequestContext can be null. Because the role of the
request context is to link requests to replies, it does not make sense
to have a request context when you do not have a reply, and so in this
case the context is set to null. For a one-way operation on top of the
request/reply model, the server receives requests but does not send
back a response to the client. So if the RequestContext is null
unexpectedly, check first whether the operation contract is IsOneWay.
Qouted from https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.channels.requestcontext?view=netframework-4.7.2
The Request context is null when a one way response is specified on the OperationContract header.
The RequestContext can be accessed by using
rcontext = operationContext.RequestContext
I have added a WCF service reference to Silverlight application and here's what the binding from web.config that I have looks like
<bindings>
<wsDualHttpBinding>
<binding name="wsDualHttpBinding">
<security mode="None" />
</binding>
</wsDualHttpBinding>
<pollingDuplexHttpBinding>
<binding name="multipleMessagesPerPollPollingDuplexHttpBinding"
duplexMode="MultipleMessagesPerPoll" />
</pollingDuplexHttpBinding>
</bindings>
And I have this snippet to create a service client instance
var serviceClient = new DuplexCallerIdServiceClient(
new PollingDuplexHttpBinding(PollingDuplexMode.MultipleMessagesPerPoll),
new EndpointAddress("http://localhost:51445/Service/MyService.svc"));
My concern is that why do I have to provide an absolute url in code. I have a winforms application that uses the same service and I can just do new DuplexCallerIdServiceClient() to create a service client instance which seems ideal. Is there any way I can work around it. I cannot change the binding settings.
Thanks
You do not have to hardcode the service URL. Replace the hard coded string that either is passed in as an argument or makes a function call (or gets some object's property) to populate the constructor with a valid service URL.
Here's one way among many:
var serviceClient = new DuplexCallerIdServiceClient(
new PollingDuplexHttpBinding(PollingDuplexMode.MultipleMessagesPerPoll),
new EndpointAddress(Info.Instance.ServiceURL));
Where Info is a singleton object, Instance gets the singleton's instance and ServiceUrl is a string property that comes from... wherever. Database, config file, hard coded to start etc...
P.S. Careful with the Singleton pattern, but as config info entities they can be very useful.
Hello i have problem accessing HttpContext.Current.Application From global.asax its seems to be null every time i try to access it.
How can i to this?
HttpContext.Current.Application.Lock();
HttpContext.Current.Application["Actions"] = "hello";
HttpContext.Current.Application.UnLock();
Thanks
In Global.asax, you're not in an actual request, so there's no current request nor context you can go by. However, the Global class is a subclass of HttpApplication, so just use 'this', like:
this["Actions"]
From MSDN
To get the HttpApplication object for the current HTTP request, use ApplicationInstance. (ASP.NET uses ApplicationInstance instead of Application as a property name to refer to the current HttpApplication instance in order to avoid confusion between ASP.NET and classic ASP. In classic ASP, Application refers to the global application state dictionary.)
You need to turn on access to the Application instance object in your web.config file like so:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
Be sure to include a reference to System.Web.