RESTful WCF Service – How to get browser version at server code

At our product we have a client Silverlight part and server-code part, which contains a lot of WCF methods. We don’t use ASP.NET Compatible mode, because we want to leave an opportunity to deploy server part to server without web-server role (without IIS). Really, I don’t know why we chose this way, because all of our installations at current moment are on IIS. But we have what we have, so we haven’t ASP.NET Compatible mode, and as an expected result we can’t get HttpContext.Current instance at server WCF methods. One of WCF Service is a RESTful service, which at his methods returns report files, so it can handle GET-queries from browsers. This is standard code:

WebOperationContext context = WebOperationContext.Current;
context.OutgoingResponse.ContentLength = reportBytes.Length;
context.OutgoingResponse.ContentType = "application/pdf";
context.OutgoingResponse.Headers.Set("content-disposition", "attachment;filename=" + fileName);

But we got a problem. Some files contain spaces at their names, and different browsers handle these names by their ways. First problem was: if variable filename contains name like “file with spaces.pdf”, then FireFox will show us only “file”, we solved this problem easy, need to surround file name with quotes (Really, I don’t know how many times I have been writing this code and always get the same problems):

context.OutgoingResponse.Headers.Set("content-disposition", "attachment;filename=\"" + fileName + "\"");

Internet Explorer has his own way to handle filenames with spaces. It replaces spaces with symbol ‘_’. I was trying to solve this problem with this code:

filename = HttpUtility.UrlPathEncode(filename);

After this line variable filename will has value “filename%20with%20spaces.pdf” and Internet Explorer now saves file with correct name, but FireFox leave %20 instead of spaces. So I need a way to get information at server code which browser asked file. I wrote method IsInternetExplorer:

private bool IsInternetExplorer()
{
  WebOperationContext context = WebOperationContext.Current;
  if (context != null)
  {
    string userAgentInfo = context.IncomingRequest.Headers["User-Agent"];
    if (userAgentInfo != null)
      return userAgentInfo.Contains("MSIE");
  }
  return false;
}

So I place plug for Internet Explorer in server code:

if (IsInternetExplorer())
  filename = HttpUtility.UrlPathEncode(filename);

It was a surprise for me, that I couldn’t find a way to get browser version in internet. But I knew that should be the way to get user-agent string from request. At first I wrote realization with OperationContext:

private bool IsInternetExplorer()
{
  OperationContext context = OperationContext.Current;
  HttpRequestMessageProperty httpRequest = context.IncomingMessageProperties["httpRequest"] as HttpRequestMessageProperty;
  if (httpRequest != null)
  {
    string userAgentInfo = httpRequest.Headers["User-Agent"];
    if (userAgentInfo != null)
      return userAgentInfo.Contains("MSIE");
  }
  return false;
}

But then I remembered about WebOperationContext. I think that WCF is not transparent. I will try in future to learn more about WCF and maybe will try to pass MS exam about WCF.

Comments (5)

IEBlog ( ) #
gravatar
Test for browser capabilities, not user agent strings.
Denis Gladkikh ( ) #
gravatar
IEBlog, sorry, couldn't get you. How "browser capabilities" will help me?
john ( ) #
gravatar
hello denis,

i face problem during consume rest webservice in silverlight.could u please help me. here is my code and exception.

public getUsers()

{

string uri = "http://192.168.100.14:30000/users";

var client = new WebClient();

client.DownloadStringCompleted += ClientCallUsersCompleted;

client.DownloadStringAsync(new Uri(uri, UriKind.Absolute));

} public void ClientCallUsersCompleted(object sender, DownloadStringCompletedEventArgs e)

{

try

{

//handle the response.

string result = e.Result;

MessageBox.Show(result);



}

catch (Exception ex)

{

//MessageBox.Show(ex.ToString());

}



}

{System.Reflection.TargetInvocationException: An exception occurred during the operation, making the result invalid. Check InnerException for exception details. ---> System.Security.SecurityException ---> System.Security.SecurityException: Security error.

at System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)

at System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClass5.b__4(Object sendState)

at System.Net.Browser.AsyncHelper.<>c__DisplayClass2.b__0(Object sendState)

--- End of inner exception stack trace ---

at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)

at System.Net.Browser.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)

at System.Net.WebClient.GetWebResponse(WebRequest request, IAsyncResult result)

at System.Net.WebClient.DownloadBitsResponseCallback(IAsyncResult result)

--- End of inner exception stack trace ---

at System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary()

at System.Net.DownloadStringCompletedEventArgs.get_Result()

at SilverlightApplication4.MainPage.ClientCallUsersCompleted(Object sender, DownloadStringCompletedEventArgs e)}
Denis Gladkikh ( ) #
gravatar
Hi, john

Sorry I can't help you in this problem.
john ( ) #
gravatar
ok thanks, i got here is the solution http://www.codebadger.com/blog/post/2010/06/02/Cross-domain-access-for-trusted-Silverlight-4-applications-(With-XBOX-Live-Avatars!).aspx#comment
Submit Comment
If you want to get notifications about new comments at this topic, please fill email text box and check proper item. If you want to place source code in comment body place it in tags [code]...[/code], you can set language like this [code cs]...[/code], where cs can be cs, html, xml, java, js, php, sql, cpp, css.

 

busy