Silverlight, WCF, and Cross Domain


Last night I was trying to consume a WCF service using Silverlight and I ran into the Cross Domain problem that a lot of people have already ran into. Here’s the message of the exception:

An error occurred while trying to make a request to URI 'http://localhost:1292/WASService/Service.svc/Service'. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. This error may also be caused by using internal types in the web service proxy without using the InternalsVisibleToAttribute attribute. Please see the inner exception for more details.

I have already heard about this error and I knew that it could easily be solved by adding clientaccesspolicy.xml and/or crossdomain.xml to the root of the application. You can find a very detail description of when you are attempting to go across domains in this forum: http://forums.silverlight.net/forums/p/24005/86700.aspx (look for sladapter answer). You can also find more info on by reading the Network Security Access Restrictions in Silverlight. The problem I was having is that both of the files were already in the root of the application.

image

I decided to use firebug to see what was going on:

image

and that’s when it hit me. Silverlight is trying to access the xml files on the root of the webserver, not on the root of the application. My files are located on http://localhost:1292/WASService/clientaccesspolicy.xml and http://localhost:1292/WASService/crossdomain.xml. “Easy fix,” I thought, “just change the files to the root.” The problem is that this is hosted using the WebDevServer (Cassini) and there is no root folder. It turns out that Scott Guthrie wrote about running the app as a root with the local web server. So All I had to do was to bring the properties of the project (F4 on the project) and change the Virtual path from “/WASService” to “/”.

image

Now all I had to do was change the service reference on the Silverlight app and I was up and running in no time.

image

Happy programming!

author: Jonas Stawski | posted @ Friday, February 05, 2010 10:07 AM | Feedback (0)

Problem Creating a Localized, Embedded Script


I was following this tutorial and was getting the error: Assembly 'AssemblyName' contains a Web resource with name 'ResourceName', but does not contain an embedded resource with name 'ResourceName'. Everything seemed to be perfect except that I forgot to set the JS file to build as an Embedded Resource:

image

Happy Programming!

author: Jonas Stawski | posted @ Saturday, January 16, 2010 3:42 PM | Feedback (1)

Follow All Microsoft MVPs through Twitter


Scott Dorman created a list where you can follow all Microsoft MVPs through Twitter. Go ahead and follow us. If you’re an MVP and are not in the list you can let @sdorman know.

Happy Twitting!

author: Jonas Stawski | posted @ Tuesday, January 05, 2010 7:09 PM | Feedback (1)

Windows Phone Camp 2009 – Tampa Bay


The first Windows Phone Camp 2009 in Tampa is around the corner. I wouldn’t miss it if I were you. The idea is to be similar to a Code Camp, but for Windows Mobile development. You get 8 sessions one after the other from getting started, to using the GPS, to building games. There will be free lunch and lots of prizes.

The date is December 5th, mark your calendars…

Happy WM Programming!

author: Jonas Stawski | posted @ Monday, November 30, 2009 12:28 PM | Feedback (1)

Powershell Script for Compressing DB Backups


The following Powershell script compresses all the .BAK files using winrar.

   1: cd D:\MSSQL\MSSQL.1\MSSQL\Backup
   2: $dirs = get-childitem|where{$_.PSIsContainer}
   3: foreach ($dir in $dirs) {
   4:     cd $dir
   5:     $files = get-childitem *.bak
   6:     foreach ($file in $files) {
   7:         #Check for null
   8:         if ($file -ne $NULL){
   9:             #write-host $file.Name.Replace(".bak", "")
  10:             & "c:\program files\winrar\rar" a $file.Name.Replace(".bak", "") $file.Name
  11:             remove-item $file
  12:         }
  13:     }
  14:     cd ..
  15: }

Walk through:

1. Change directory to the backup root directory
2. Get all the subdirectories and iterates through each one
3. Get all *.BAK files and iterate through them
4. Use the winrar command line to compress the file
5. remove the .BAK file

Happy Powershelling!

author: Jonas Stawski | posted @ Monday, November 16, 2009 1:43 PM | Feedback (1)

Out of Process Session State and LINQ To SQL Entities


When using ASP.NET you can choose 4 different ways of storing session: In Process, State Server, SQL Server, or Custom. When using In Process the session is stored on the ASP.NET thread of the web server, but when using the State Server or SQL Server the sessions are stored outside the ASP.NET thread. When would you use Out of Process session state? Mostly when you have a web farm and you need to share the same session across all web servers. You might choose to use it even if you have one web server for the simple reason of saving memory on the web server.

When using In Process and you store an object in session, ASP.NET maintains the object in memory and holds a pointer to that object so it can be used on future requests. Based on this explanation you should be able to store almost any object in session, including LINQ to SQL Entities.

The problem arises when you use Out of Process Session State. Whether you use SQL Server or State Server the objects need to be serializable in order to be able to be persisted. The object graph of a LINQ to SQL entity can be very complex and you will need to make every single child entity and type serializable, which can become very cumbersome. I came up with a simple solution that is to serialize all objects when setting them in session and deserialize them when retrieving them from session. In order for this to work you have to make sure that your L2S entities are decorated with the DataContract attribute and the properties are also decorated with the DataMember attribute. If you generate your entities using SqlMetal then you can do so by using the /serialization:Unidirectional parameter or if you use the VS designer by right clicking on the design surface and specify “Uniderectional” in property grid for “Serialization Mode”.

Here are the helper methods:

   1: public static MemoryStream Serialize<T>(T obj)
   2: {
   3:     DataContractSerializer s = new DataContractSerializer(typeof(T));
   4:     MemoryStream ms = new MemoryStream();
   5:     s.WriteObject(ms, obj);
   6:  
   7:     return ms;
   8: }
   9:  
  10: public static T Deserialize<T>(MemoryStream ms)
  11: {
  12:     DataContractSerializer s = new DataContractSerializer(typeof(T));
  13:     ms.Position = 0;
  14:     T retObject = (T)s.ReadObject(ms);
  15:  
  16:     return retObject;
  17: }

A sample on how to use them:

   1: //Store in session
   2: Session["User"] = Serialize(user);
   3:  
   4: //Retrieve from session
   5: User user = Deserialize<User>(Session["User"] as MemoryStream);

Something to be aware of is that by serializing and deserializing a L2S entity you are detaching the entity from the datacontext and hence there will be no lazy loading of child objects nor insertions or updates of that entity. In other words the entity becomes a Plain Old CLR Object (POCO).

Happy Programming!

author: Jonas Stawski | posted @ Friday, November 13, 2009 11:56 AM | Feedback (1)

JavaScript not working within UpdatePanel


The other day I was having a problem with JavaScript functions not being found. The simplified setup was similar to this:

- UpdatePanel
   - UserControl (Visible = true)
   - UserControl (Visible = false)
      - Embedded JavaScript and Controls

There was some controls on the page that triggered an asynchronous postback which changed the visibility of the UserControls and when the Embedded JavaScript was called I was getting JS errors. Here’s the question I asked on the forums: http://forums.asp.net/t/1484503.aspx.

According to InfinitiesLoop:

The over simplified way of explaining how UpdatePanel does its work on the client is through the innerHTML DOM property. When a delta is retrieved from the server, it finds itself in the existing DOM, disposes of the contents, and then assigns the new content via innerHTML. Thanks to a basically consistent behavior across the major browsers, the new content appears just as if it were there to begin with.

But inline script doesn't work this way. Setting the innerHTML of a DOM element to HTML which contains a script block does not cause that script to execute. The only way to execute arbitrary script dynamically is to eval() it directly, or dynamically create a script element with document.createElement("script") and inject it into the DOM.

So to solve my problem I dynamically created the embedded JS through the use of the ScriptManager on the Page Load:

   1: ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "SomeUniqueID", "function HelloWorld() { alert('Hello World'); }", true);


Happy Programming!

author: Jonas Stawski | posted @ Monday, November 02, 2009 9:03 AM | Feedback (0)

2009 Buenos Aires CodeCamp – Presentations Available


Presentations from the 2009 Buenos Aires CodeCampare now available through the official Argentina TechNet and MSDN Facebook Page. You can find the content under the “Contenidos Tecnicos”: http://www.facebook.com/ComunidadesMicrosoft?v=app_7146470109&ref=nf

Happy Programming!

author: Jonas Stawski | posted @ Wednesday, October 07, 2009 2:49 PM | Feedback (0)

Se viene el Buenos Aires Code Camp 2009


Este año va a ser aun mas grande que el año pasado. Tenemos 12 charlas en paralelo en 4 horarios diferentes. Más de 50 oradores del todo el país compuesto por MVPs, MSPs, empleados de Microsoft, profesionales y estudiantes. Algunos de los temas son Windows y SQL Admin, ASP.NET, .NET 4.0, WPF, Silverlight, XNA, y mucho mas.

El evento es el Sábado, 26 de Septiembre a de 10:00 a 19:00 en la Universidad de Palermo.

Te lo vas a perder? http://www.codecamp.com.ar/home.aspx

author: Jonas Stawski | posted @ Friday, September 11, 2009 12:01 PM | Feedback (0)

Sample Code for Getting the User Location based on the IP Address


Yesterday I introduced a free service to get the location of the IP Address. If you haven’t read it, go on read that first (it’s very short, I promise). So here I am today, showing you my small .NET API to abstract the XML returned by the service.

First we need an object to hold the data. I called it UserLocation.

   1: public class UserLocation
   2: {
   3:     public string City { get; set; }
   4:     public string Country { get; set; }
   5:     public string CountryAbbrev { get; set; }
   6:     public double Latitude { get; set; }
   7:     public double Longitude { get; set; }
   8: }

Then I created a helper class to retrieve the info. I called it GeoLocation:

   1: public class GeoLocation
   2: {
   3:     //you might want to retrieve this from a config file
   4:     private static string ServiceAddress = "http://api.hostip.info/?ip={0}";
   5:     public static UserLocation Locate(string ipAddress)
   6:     {
   7:         string url = String.Format(ServiceAddress, ipAddress);
   8:         //Get the XML from the request
   9:         XmlDocument xml = GetXml(url);
  10:         //Parse the XML into a UserLocation
  11:         return ParseUserLocation(xml);
  12:     }
  13:  
  14:     private static XmlDocument GetXml(string url)
  15:     {
  16:         HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
  17:         myReq.Method = "GET";
  18:         HttpWebResponse myResp = null;
  19:         XmlDocument xml = null;
  20:         try
  21:         {
  22:             myResp = (HttpWebResponse)myReq.GetResponse();
  23:             if (myResp != null && myResp.StatusCode == HttpStatusCode.OK)
  24:             {
  25:                 Stream dataStream = myResp.GetResponseStream();
  26:                 StreamReader reader = new StreamReader(dataStream);
  27:                 xml = new XmlDocument();
  28:                 xml.LoadXml(reader.ReadToEnd());
  29:  
  30:                 reader.Close();
  31:                 dataStream.Close();
  32:                 myResp.Close();
  33:             }
  34:         }
  35:         catch
  36:         {
  37:             xml = null;
  38:         }
  39:  
  40:         return xml;
  41:     }
  42:  
  43:     private static UserLocation ParseUserLocation(XmlDocument xml)
  44:     {
  45:         UserLocation location = null;
  46:         if (xml != null)
  47:         {
  48:             try
  49:             {
  50:                 XmlNamespaceManager nsMgr = new XmlNamespaceManager(xml.NameTable);
  51:                 nsMgr.AddNamespace("gml", "http://www.opengis.net/gml");
  52:                 
  53:                 XmlNode node = xml.SelectSingleNode("/HostipLookupResultSet/gml:featureMember/Hostip", nsMgr);
  54:                 if (node != null)
  55:                 {
  56:                     location = new UserLocation();
  57:                     XmlNode childNode = node.SelectSingleNode("gml:name", nsMgr);
  58:                     if (childNode != null)
  59:                         location.City = childNode.InnerText;
  60:  
  61:                     childNode = node.SelectSingleNode("countryName", nsMgr);
  62:                     if (childNode != null)
  63:                         location.Country = childNode.InnerText;
  64:  
  65:                     childNode = node.SelectSingleNode("countryAbbrev", nsMgr);
  66:                     if (childNode != null)
  67:                         location.CountryAbbrev = childNode.InnerText;
  68:  
  69:                     childNode = node.SelectSingleNode("ipLocation/gml:pointProperty/gml:Point/gml:coordinates", nsMgr);
  70:                     if (childNode != null)
  71:                     {
  72:                         string[] coord = childNode.InnerText.Split(',');
  73:                         if (coord.Length == 2)
  74:                         {
  75:                             double tmp = 0.0;
  76:                             double.TryParse(coord[0], out tmp);
  77:                             location.Longitude = tmp;
  78:                             double.TryParse(coord[1], out tmp);
  79:                             location.Latitude = tmp;
  80:                         }
  81:                     }
  82:  
  83:                     //make it null because it couldn't find it
  84:                     if (location.CountryAbbrev == "XX")
  85:                         location = null;
  86:                 }
  87:             }
  88:             catch
  89:             {
  90:                 location = null;
  91:             }
  92:         }
  93:         return location;
  94:     }
  95: }

As you can see. First we use the request API from .NET to make a request to the service and parse the request into an XML. Then we use the XML to parse it into our UserLocation object which will then be used by our web application. This is not a critical part of my application, so I decided that for any problem that I might encounter I will return null. In the web app I will only use the information if it’s not null.

   1: UserLocation location = GeoLocation.Locate(Request.UserHostAddress);
   2: if (location != null)
   3: {
   4:     //TODO: Do something with it
   5:     //location.City
   6:     //location.Country 
   7:     //location.CountryAbbrev 
   8:     //location.Latitude
   9:     //location.Longitude 
  10: }

The code above shows how to use the GeoLocation helper method from the web page or any other object.

Enjoy and Happy Programming!

author: Jonas Stawski | posted @ Thursday, September 03, 2009 2:01 PM | Feedback (1)