Set your FileAccess!
When I was working on the latest release of the BlogThisUsingPostXINGPlugin, I kept running into file access issues.
The whole thing was an excersize in refactoring - well, really, the whole thing WAS a refactor, since the basic functionality already existed, but I was making additions in how things were going to work.
First, I changed the XsltStream to return a FileStream or a ManifestResourceStream, based on the existence of a user-specific file:
1 Stream XsltStream 2 { 3 get 4 { 5 string filePath = Path.Combine(ConfigurationPath, this.BlogType.ToString() + ".xslt"); 6 if(File.Exists(filePath)){ 7 //read from a file stream. 8 FileStream fs = new FileStream(filePath, FileMode.Open); 9 return (Stream)fs; 10 }else{ 11 string resourceName = "PostXING.Rss.BlogExtensions.Resources." + this.BlogType.ToString() + ".xslt"; 12 return Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName); 13 } 14 } 15 }
Again, this part was shamelessly lifted modified from
haacked who generously gave out the source
code for his BlogThisUsingWbloggarPlugin. (the configurationPath property was
changed a bit to enable more than one file to go into that particular path).
Then I added a button next to each option in the config dialog that says simply “Customize…”. Pressing this button opens a modal form that loads up the text from the user-defined file if it exists, else from the resource stream.:
1 string transformPath; 2 3 public CustomizeForm() 4 { 5 // 6 // Required for Windows Form Designer support 7 // 8 InitializeComponent(); 9 10 } 11 12 public CustomizeForm(string TransformToCustomize) : this(){ 13 transformPath = Path.Combine(BlogThisUsingPostXINGPlugin.ConfigurationPath, string.Format("{0}.xslt", TransformToCustomize)); 14 15 this.LoadTransform(TransformToCustomize); 16 } 17 18 private void LoadTransform(string TransformToCustomize){ 19 string resourceName = string.Format("PostXING.Rss.BlogExtensions.Resources.{0}.xslt", TransformToCustomize); 20 //Stream resourceStream; 21 StreamReader sr; 22 23 if(File.Exists(transformPath)){ 24 sr = new StreamReader(transformPath); 25 this.rtbTransform.Text = sr.ReadToEnd(); 26 sr.Close(); 27 28 }else{ 29 sr = new StreamReader(ResourceStream(resourceName)); 30 this.rtbTransform.Text = sr.ReadToEnd(); 31 sr.Close(); 32 33 } 34 } 35 36 Stream ResourceStream(string resourceName){ 37 return Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName); 38 }
3 buttons were added to the form: Revert to Original, Apply, and Cancel. I didn’t really think that I needed DialogResults, since you have to invoke the plugin via its menu every time you want to use it. Revert to Original just deletes the user-defined file. Cancel simply closes the form and does nothing. Apply does this:
1 private void btnApply_Click(object sender, System.EventArgs e) { 2 if(File.Exists(transformPath)){ 3 File.Delete(transformPath); 4 } 5 6 StreamWriter sw = new StreamWriter(transformPath, false); //doesn't release file handle? 7 sw.Write(this.rtbTransform.Text); 8 sw.Flush(); 9 sw.Close(); 10 11 this.Close(); 12 }
Notice my little note to myself? It turned out that I tried using the using statement, using File.CreateText(transformPath) (which is why the pre-step File.Delete is in there) and I kept getting “Cannot access file ‘blah’ because it is in use by another process.” When I opened up sysinternal’s process explorer and searched for the file, it said that the file handle was opened by RssBandit. grr.
All I ended up having to do was to add one argument to File.Open from the XsltStream property getter:
1 Stream XsltStream 2 { 3 get 4 { 5 string filePath = Path.Combine(ConfigurationPath, this.BlogType.ToString() + ".xslt"); 6 if(File.Exists(filePath)){ 7 //read from a file stream. 8 FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); 9 return (Stream)fs; 10 }else{ 11 string resourceName = "PostXING.Rss.BlogExtensions.Resources." + this.BlogType.ToString() + ".xslt"; 12 return Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName); 13 } 14 } 15 }
And bam! the problem went away. It looks like the default for a new FileStream (sans FileAccess attribute) is FileAccess.ReadWrite. Anyways, I hope this helps someone else out there from banging their head too much.
[ Currently Playing : Inertiatic ESP - Mars Volta - De-Loused In The Comatorium (4:23) ]