URI References for App Resources

摘要:URI References for App Resources

Silverlight 2: Demystifying URI references for app resources

In this post we will look at how application data files can be referenced using relative Uris from within XAML or code in your Silverlight 2 application.

Silverlight provides you with a luxury of choices for how you declare your application data files. These are the non-code artifacts of your app, such as images, videos, fonts etc. The build action for any file - i.e. how you declare it in your project file or within Visual Studio or Blend - is consequential to how it can be referenced in XAML or code via a Uri. While care was taken to ensure defaults that gel with the programmers intuitiveness while referencing them in Uris, there are always subtle issues that the intrepid Silverlight designer or developer must be aware of. If you come to Silverlight with previous WPF experience, the contents of this post should be old news to you. If not, fear not; Silverlight is designed to be easy to learn and easy to master.

Let's take Image files as an example as we walk through the various cases. Once you understand how this works, you can extrapolate behavior for MediaElement (audio/video) or MultiScaleImage (SeaDragon in Silverlight) or perhaps even fonts. While examples below show XAML syntax, the same applies to code.

Files marked as Resource:

  • Get embedded in the app assembly within the XAP
  • Are accessible using a relative Uri, relative to the XAML file from where they are being referenced
    For e.g. <Image Source=”Foo.jpg” />
  • When not found, there is no fallback. The ImageFailed event is raised.

Tip: Using assembly qualified Uris is most reliable both from within and outside that assembly. E.g. <Image Source=”/{assemblyShortName};component/Foo.jpg”/>

Tip: You can programmatically extract any application resource using Application.GetResourceStream(uri).Stream.

Files marked as Content:

  • Get added to the XAP at the conceptual application root
  • Are accessible using a relative Uri, relative to the application root. This requires the use of a leading slash
    For e.g. <Image Source=”/Foo.jpg” />
  • When not found, the resource loading mechanism falls back to the application’s site of origin and looks for the image under the same (web root) dir as the XAP is located
  • When not found, the ImageFailed event is raised.

Tip: this is a no-brainer when you have a resource that is commonly used from within 2 assemblies in the XAP

Files marked as None (with CopyToOutputDirectory set appropriately):

  • Don’t get copied into the XAP, but the CopyToOutputDirectory metadata will ensure it gets copied alongside the XAP
  • Are accessible using a relative Uri, relative to the application root. This requires the use of a leading slash
    For e.g. <Image Source=”/Foo.jpg” />
  • This is the fallback path of the above

Tip: in most cases you want to keep your video files out of the XAP. They are not encumbered by x-domain download restrictions. You do not get compression benefits from keeping them in the XAP. Rather you can use streaming or progressive download if they are outside.

Files marked as None, as well as image and audio/video files not marked at all in the project (i.e. external to the project), can always be referenced using absolute Uris.

Files marked as EmbeddedResource:

  • Get embedded into the assembly in a manner that Silverlight cannot use for URI references either from XAML or code
  • Should be changed to Resource, and used as detailed above.

 

Hopefully this demystifies Uri usage in Silverlight for you. If we can make improvements in the runtime or in tools to make this easier for you, please post a comment here. Feedback is always appreciated.

 

 

Different ways to access XML data in Silverlight Application

One of the most common requirement in the Silverlight development is to load XML data in to the application. I am going to describe a few different options that we can choose based on the situations. I am using LINQ for the XML parsing in the examples. Taking a sample XML file names Sample.xml with the following content

<Employees>
  <Employee Name="John"/>
  <Employee Name="Mark"/>
  <Employee Name="David"/>
</Employees> 

1. Load XML file directly from the Web Server hosted Silverlight XAP

You can host the XML file at your web server itself and Silverlight application can load it on demand. To simulate this in Visual Studio you need to create a Test Website for your Silverlight application and put xml file into the ClientBin folder.

image

Now we can write few lines of code to read the XML. WebClient will download the file asynchronously

void Page_Loaded(object sender, RoutedEventArgs e)
{
WebClient xmlClient = new WebClient();
xmlClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(XMLFileLoaded);
xmlClient.DownloadStringAsync(new Uri("Sample.xml", UriKind.RelativeOrAbsolute));
}
void XMLFileLoaded(object sender, DownloadStringCompletedEventArgs e)
{
  string XmlString = e.Result; // Got all your XML data in to a string 
XDocument elem = XDocument.Load(XmlReader.Create(new StringReader(XmlString)));
var collection = from nod in elem.Descendants("Employee")
      select nod.Attribute("Name").Value;
lstBox.ItemsSource = collection ; // XML data bind to the UI
}

2. Load XML file directly from the Silverlight App(XAP)

image

Add the XML file as a content to the Silverlight project. This is the easiest way to build and deploy a Silverlight project, since you really don't need to worry about the XML file once it is placed as part of the project. When you compile, it will automatically embed the XML file inside the XAP file. But the big problem is that you can’t easily change the XML data after the deployment. . And here the C# to read data from this situation
 

 XDocument elem = XDocument.Load("Sample.xml");
var collection = from nod in elem.Descendants("Employee")
  select nod.Attribute("Name").Value;

3. Load XML file from one of the Silverlight Assemblies

When you have more than one Silverlight class libraries associated with a Silverlight application, it may be meaningful to add the XML file to a different project than the main project. So this case you need to add the file as an EmbeddedResource.

image

  Stream stream = this.GetType().Assembly.GetManifestResourceStream("XmlLoadingTest.Sample.xml");
 XDocument elem = XDocument.Load(XmlReader.Create(stream));
 var coll = from nod in elem.Descendants("Employee")
    select nod.Attribute("Name").Value;

4. Load XML file from a URI

This is the case of accessing third party data from feeds and services. It is a big security threat to access resources from a server where the XAP file didn't not originate. So the server you are requesting access needs a special permission files hosted. You can read more about this here-Making a Service Available Across Domain Boundaries) and here-Network Security Access Restrictions in Silverlight 2

When coming to read this kind of hosted XML urls from C#, you can use either step(1) or step(2) of the above C# code snippets. I prefer the step(1) option because it is asynchronous and will not hang up the UI. And also it will not make the XAP size larger with larger XML files, so the initial loading will be faster.