views:

56

answers:

3

I have a text file with a list of 300,000 words and the frequency with wich they occur. Each line is in the format Word:FequencyOfOccurence. I want this information to be accessible from within the C# code. I can't hard code the list since it is too long, and I'm not sure how to go about accessing it from a file on the server. Ideally I'd ideally like the information to be downloaded only if it's used (To save on bandwidth) but this is not a high priority as the file is not too big and internet speeds are always increasing. It doesn't need to be useable for binding. The information does not need to be editable once the project has been built.

A: 

You could create a WCF service on the server side that will send the data to the Silverlight application. Once you retrieve the information you could cache it in-memory inside the client. Here's an example of calling a WCF service method from Silverlight.

Another possibility is to embed the text file into the Silverlight assembly that is deployed to the client:

using (var stream = Assembly.GetExecutingAssembly()
                            .GetManifestResourceStream("namespace.data.txt"))
using (var reader = new StreamReader(stream))
{
    string data = reader.ReadToEnd();
    // Do something with the data
}
Darin Dimitrov
If I can't find a better option I'll try that, the thing is I'd rather not place any extra requirements on the server in terms of scripting etc. One of my reasons for choosing silverlight is that it does not need any special features (server side) to host it.
Tuskan360
A: 

Based on your comments, you could download the word list file if you are required to have a very thin server layer. The XAP file containing your Silverlight application is nothing more than a ZIP file with all the referenced files for your Silverlight client layer. Try adding the word list as content that gets compiled into the XAP and see how big the file gets. Text usually compresses really well. In general, though, you'll want to be friendly with your users in how much memory your application consumes. Loading a huge text file into memory, in addition to everything else you need in your app, may untimately make your app a resource hog.

A better practice, in general, would be to call a web service. The service could would perform whatever look up logic you need. Here's a blog post from a quick search that should get you started: (This was written for SL2, but should apply the same for SL3.)

Calling web services with Silverlight 2

Even better would be to store your list in a SQL Server. It will be much easier and quicker to query.

Mike
The same applies with not ideally wanting to have to host a web service, however there is no requirement for it to be a text file, that's simply where the data is now, I could easilly enough add it to an SQL database.
Tuskan360
Since this feature will not always be used, I think you're right that it shouldn't be compiled in with the app (it adds about 1.5MB to the download size)As an alternative (to keep the server side code thin), I am going to use System.Windows.Browser.HtmlPage.Window.Navigate to allow the user to manually download a file. Since this will only need to be done once, it shouldn't be too much of an issue.
Tuskan360
@Tuskan360: That seems like an odd choice, why not download it with WebClient when needed from within the Silverlight app. Configure cache control headers correctly in order to avoid repeated downloads.
AnthonyWJones
I couldn't get that to work when I first tried it, but the code from AnthonyWJones worked so I'm using that now.
Tuskan360
+2  A: 

Here is another alternative. Zip the file up and stick it in the clientBin folder next to the apllication XAP. Then at the point in the app where the content is needed do something like this:-

 public void GetWordFrequencyResource(Action<string> callback)
 {
     WebClient client = new WebClient();
     client.OpenReadAsync += (s, args) =>
     {
       try
       {
         var zipRes = new StreamResourceInfo(args.Result, null)
         var txtRes = Application.GetResourceStream(zipRes, new Uri("WordFrequency.txt", UriKind.Relative));
         string result = new StreamReader(txtRes.Stream).ReadToEnd();

         callback(result);
       }
       catch
       {
         callback(null);  //Fetch failed.
       } 

     }
     client.OpenReadAsync(new Uri("WordFrequency.zip", UriKind.Relative"));
 }

Usage:-

 var wordFrequency = new Dictionary<string, int>();
 GetWordFrequencyResource(s =>
 {
    // Code here to burst string into dictionary.
 });
 // Note code here is asynchronous with the building of the dictionary don't attempt to 
 // use the dictionary here.

The above code allows you to store the file in an efficient zip format but not in the XAP itself. Hence you can download it on demand. It makes use of the fact that a XAP is a zip file so Application.GetResourceStream which is designed to pull resources from XAP files can be used on a zip file.

BTW, I'm not actually suggesting you use a dictionary, I'm just using a dictionary as simple example. In reality I would imagine the file is in sorted order. If that is the case you could use a KeyValuePair<string, int> for each entry but create a custom collection type that holds them in an array or List and then use some Binary search methods to index into it.

AnthonyWJones
Replace:client += (s, args) =>With:client.OpenReadCompleted += (s, args) =>Replace:var zipRes = new StreamResourceInfo(e.Result, null)With:var zipRes = new StreamResourceInfo(args.Result, null);And don't forget to replace both file names with the correct ones.Otherwise perfect, many thanks as this is exactly the solution I was after.
Tuskan360
@Tuskan360: Edited accordingly, I cranked it out a little to quickly.
AnthonyWJones