Client IP address in ASP.NET (.asmx) webservices - asp.net

I am using ASP.NET (.asmx) web services with Silverlight. Since there is no way to find the client IP address in Silverlight, I had to log this on the service end.
These are some methods I have tried:
Request.ServerVariables("REMOTE_HOST")
HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]
HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
Request.UserHostAddress()
Request.UserHostName()
string strHostName = Dns.GetHostName();
string clientIPAddress = Dns.GetHostAddresses(strHostName).GetValue(0).ToString();
All the above methods work fine on my local system, but when I publish my service on a production server, it starts giving errors,
Error: Object reference not set to an instance of an object. StackTrace:
at System.Web.Hosting.ISAPIWorkerRequestInProc.GetAdditionalServerVar(Int32 index)
at System.Web.Hosting.ISAPIWorkerRequestInProc.GetServerVariable(String name)
at System.Web.Hosting.ISAPIWorkerRequest.GetRemoteAddress()
at System.Web.HttpRequest.get_UserHostAddress()

You should try to find out exactly where the NullReferenceException is coming from. Change your code to understand that certain things can return null. For instance, in
HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]
HttpContext.Current could retrun null, or .Request could return null, or .ServerVariables["REMOTE_ADDR"] could return null. Also, in
string clientIPAddress = System.Net.Dns.GetHostAddresses(strHostName).GetValue(0).ToString();
the GetHostAddresses(strHostName) could return null, or the .GetValue(0) could return null.
If a method or property could return null, then you should check for null before dereferencing it. For instance,
IPAddress[] hostAddresses = System.Net.Dns.GetHostAddresses(strHostName);
string clientIPAddress;
if (hostAddresses != null)
{
object value = hostAddresses.GetValue(0);
if (value != null)
{
clientIPAddress = value.ToString();
}
}
P.S. I don't know why you'd use GetValue(0). Use hostAddresses[0] instead.

If you take a look using Reflector at the System.Web.Hosting.ISAPIWorkerRequestInProc.GetAdditionalServerVar code, that's what we see:
private string GetAdditionalServerVar(int index)
{
if (this._additionalServerVars == null)
{
this.GetAdditionalServerVariables();
}
return this._additionalServerVars[index - 12];
}
I see two reasons why this could raise a NullReferenceException:
1) there is a multithreading issue on the _additionalServerVars member. I don't think this could happen because A) I don't see why there would be big load on your server during test, and B) the ISAPIWorkerRequestInProc instance is probably tied to a thread.
2) your server is not up to date and the code in production is not the same as the one I'm seeing on my machine.
So what I would do is check the server making sure it's up to date with the .NET Framework dlls.

Related

Replacing System.Web.Security.MachineKey.Encode with System.Web.Security.MachineKey.Protect

I just upgraded a project from .NET 4.0 to .NET 4.5.1 which produced the following warning:
Public Shared Function Encode(data() As Byte, protectionOption As
System.Web.Security.MachineKeyProtection) As String' is obsolete:
'This method is obsolete and is only provided for compatibility with
existing code. It is recommended that new code use the Protect and
Unprotect methods instead.'
I have lots of values floating around in cookies and emails that were encrypted with Encode. If I am going to replace Encode/Decode with Protect/Unprotect, I still need to be able to decrypt those old encrypted values. Is it possible to Unprotect a value that was encrypted with Encode?
In .NET 4.0 you can use MachineKey API to Protect/Unprotect data like this:
string Protect(byte[] data)
{
if (data == null || data.Length == 0) return null;
return MachineKey.Encode(data, MachineKeyProtection.All);
}
byte[] Unprotect(string value)
{
if (String.IsNullOrWhiteSpace(value)) return null;
return MachineKey.Decode(value, MachineKeyProtection.All);
}
MachineKey.Encode accepts a byte[] to protect and returns a string. The second parameter is an enum that indicates if you want encryption, validation or both. I’d typically suggest both (MachineKeyProtection.All). The returned string can then be used to pass back to the client as a cookie value or a query string value without concern for viewing or tampering. MachineKey.Decode simply reverses the process.
And here’s the 4.5 usage:
string Protect(byte[] data)
{
if (data == null || data.Length == 0) return null;
var value = MachineKey.Protect(data, "");
return Convert.ToBase64String(value);
}
byte[] Unprotect(string value)
{
if (String.IsNullOrWhiteSpace(value)) return null;
var bytes = Convert.FromBase64String(value);
return MachineKey.Unprotect(bytes, "");
}
In 4.5 the old APIs are deprecated in favor of these new Protect and Unprotect APIs. The new APIs no longer accept the level of protection (they always encrypt and MAC now [which is good]) and instead now accept a new parameter which is called purpose. This purpose parameter is intended to act somewhat as a validation mechanism. If we use a value that’s specific to the user (as we do above with the GetMachineKeyPurpose helper) we then are verifying that the value can only be unprotected by the same user. This is a nice addition in 4.5.
No - the process is different. Not to mention you'll be trying to Unprotect data that has no additional parameter specified (which won't work) and sometimes decoding data with the additional parameter specified (if you are ideally taking advantage of how protect works)
I'd refactor the code to be able to tell when the old data is present and write a new cookie/etc out using Protect();
On the first case I mentioned - you cannot use a blank parameter in Protect like
var unprotect = MachineKey.Unprotect(Encoding.UTF8.GetBytes(myOldEncryptedStuff), "");
and if you in turn have some other code there like "User 12345" to help protect that data - this is called the purpose string and helps keep that string encrypted in a more unique way tied to that user.
var unprotect = MachineKey.Unprotect(Encoding.UTF8.GetBytes(myOldEncryptedStuff), "User 12345")
If the purpose strings don't match you'll just get a generic exception here like:
System.Security.Cryptography.CryptographicException: Error occurred
during a cryptographic operation.
So it won't work for you - the two methods operate very differently. You'll need to figure out when to use one vs the other. You could always catch the exception and then try to fallback to the old tech - but test that out :)

System.Web.HttpContext.Current nulls itself after checking for a Cache

I encountered a weird issue today which made no sense to me. Here is a summary:
Inside a method, I check for a cached item as below:
private async Task<RatesStatus> getRatesStatusAsync() {
//...
if (_currentHttpContext != null) {
//Here, I am checking for a Cached item
var cachedRatesStatusObj = HttpContext.Current.Cache[Constants.RATESSTATUS_CACHE_KEY_NAME];
if (cachedRatesStatusObj != null)
return (RatesStatus)cachedRatesStatusObj;
}
//...
cacheRatesStatusObject(ratesStatus);
//...
}
Here, the HttpContext.Current is not null as expected inside an ASP.NET application. Then, inside the cacheRatesStatusObject method, I check if HttpContext.Current is null or not as below:
private void cacheRatesStatusObject(RatesStatus ratesStatus) {
//...
//Seeing if HttpContext.Current is null or not first.
//and it is null here...
if (HttpContext.Current == null)
return;
//...
}
And it is null there. No idea what is happening here. Any thoughts?
When you use async/await, the thread handling the request marks the request as incomplete and then returns to the ASP.NET thread pool. When the awaitable completes later, another thread is assigned to run the rest of the method, however HttpContext is not migrated across threads, that's why you get null reference when calling await method.
You can pass a reference of the HttpContext to the await method, something like this:
await cacheRatesStatusObject(HttpContext.Current, ratesStatus);
However you should be very careful dealing with concurrency and race conditions, for example if the await thread locks a resource and another request thread attempts to use it then your thread pool goes boom. Most people resolve this by creating new objects and passing them into paramaterized threads instead of passing a reference of HttpContext across threads.
Passing the instance sucks.
Use the .NET 4 MemoryCache classes instead.
http://stevescodingblog.co.uk/net4-caching-with-mvc/
It does not null itself.
The HttpContext is only stored in a 'thread static' way.
As suggested by the other answer, just pass the instance.

Can GetHandler return null when implementing IHttpHandlerFactory?

Will this code throw an exception:
public class MyHttpHandlerFactory : IHttpHandlerFactory
{
public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
if (...)
return null;
...
return new MyHttpHandler();
}
}
If you take a look at this article on MSDN, you'll see that in their example they return null from GetHandler. However, they only return null if the request is not a GET or a POST, which should never happen based on the way they have set up the factory in the web.config.
I set up a quick sample using the code from the article using ASP.NET 4.0/IIS 7.5/Integrated Pipeline and if you do return null from a call to GetHandler all that appears to happen is an empty 200/OK response is returned from the server (I checked using Fiddler). So it seems that ASP.NET 4.0 (at least) handles this condition gracefully. To answer the question as asked, no it does not appear that there is a runtime limitation to returning null. In practice, however, you may want to limit the requests that your HandlerFactory is receiving so that it never returns null, or at least consider how the other parts of your application will react to a request to this handler factory returning an empty 200/OK response.

Windows Azure access POST data

Ok, so I can't seem to find decent Windows Azure examples. I have a simple hello world application that's based on this tutorial. I want to have custom output instead of JSON or XML. So I created my interface like:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(UriTemplate = "session/create", Method = "POST")]
string createSession();
}
public class MyService : IService
{
public string createSession()
{
// get access to POST data here: user, pass
string sessionid = Session.Create(user, pass);
return "sessionid=" + sessionid;
}
}
For the life of me, I can't seem to figure out how to access the POST data. Please help. Thanks!
If you have an HttpContext there may be a Request object that would have the form data. I'm basing part of this off the ASP.Net tag on this question, so if that is incorrect then there may be the need to handle this another way but it looks a lot like a web service to my mind.
EDIT: HttpRequest is the class that has the Form property that should be where the POST data is stored if this is an HTTP request. This is part of System.Web so it should be ready to be used pretty easily, as I recall.
Sample code showing the Request.Form property:
int loop1;
NameValueCollection coll;
//Load Form variables into NameValueCollection variable.
coll=Request.Form;
// Get names of all forms into a string array.
String[] arr1 = coll.AllKeys;
for (loop1 = 0; loop1 < arr1.Length; loop1++)
{
Response.Write("Form: " + arr1[loop1] + "<br>");
}
This presumed there was an HttpRequest instance around.
WCF Simplified Part 4: Comparing the Request/Reply and One-Way Patterns passes in a parameter so that your "createSession" method would have to take in those strings it would appear. I'm used to the ASP.Net world where there are some built-in objects like Request, Response, Server, Application and Session.
Yes, if you did try changing the method signature as there are ways to pass in parameters in that last example I linked though I don't know if that would work in your case or not.

ASP.NET lock() doesn't work

i try to put a lock to a static string object to access to cache,, the lock() block executes in my local,but whenever i deploy it to the server, it locks forever. i write every single step to event log to see the process and lock(object) just causes the deadlock on the server. The command right after lock() is never executed as the i dont see an entry in the event log.
below is the code:
public static string CacheSyncObject = "CacheSync";
public static DataView GetUsers()
{
DataTable dtUsers = null;
if (HttpContext.Current.Cache["dtUsers"] != null)
{
Global.eventLogger.Write(String.Format("GetUsers() cache hit: {0}",dtUsers.Rows.Count));
return (HttpContext.Current.Cache["dtUsers"] as DataTable).Copy().DefaultView;
}
Global.eventLogger.Write("GetUsers() cache miss");
lock (CacheSyncObject)
{
Global.eventLogger.Write("GetUsers() locked SyncObject");
if (HttpContext.Current.Cache["dtUsers"] != null)
{
Global.eventLogger.Write("GetUsers() opps, another thread filled the cache, release lock");
return (HttpContext.Current.Cache["dtUsers"] as DataTable).Copy().DefaultView;
}
Global.eventLogger.Write("GetUsers() locked SyncObject"); ==> this is never written to the log, so which means to me that, lock() never executes.
You're locking on a string, which is a generally bad idea in .NET due to interning. The .NET runtime actually stores all identical literal strings only once, so you have little control over who sees a specific string.
I'm not sure how the ASP.NET runtime handles this, but the regular .NET runtime actually uses interning for the entire process which means that interned strings are shared even between different AppDomains. Thus you could be deadlocking between different instances of you method.
What happens if you use:
public static object CacheSyncObject = new object();

Resources