Archive
.NET String extension methods to check for array of prefixes or suffixes
Seems StartsWith and EndsWith methods of String class in .NET are missing a version that accepts multiple (as an array) prefixes or suffixes respectively when testing the string. To achieve this I just added the following extension methods to StringExtensions class (of Utils.Extensions namespace) under Utils.Silverlight project at the ClipFlair source code.
public static bool StartsWith(
this string s,
string[] suffixes,
StringComparison comparisonType = StringComparison.CurrentCulture) { foreach (string suffix in suffixes) if (s.StartsWith(suffix, comparisonType)) return true; return false; } public static bool EndsWith(
this string s,
string[] suffixes,
StringComparison comparisonType = StringComparison.CurrentCulture) { foreach (string suffix in suffixes) if (s.EndsWith(suffix, comparisonType)) return true; return false; }
To use them, you add a reference to Utils.Silverlight project to your own one and then add a using clause for the namespace that hosts a static class with these extension methods (e.g. “using Utils.Extensions;”) and then you can use them on any String at the respective source file. Can even use them on literal strings, since most .NET compilers support Boxing of literals into respective types.
I’m using a default value for the comparisonType method argument to make it optional. I use StringComparison.CurrentCulture as the default value for it (performing a word case-sensitive and culture-sensitive comparison using the current culture), as Microsoft is doing at “String.StartsWith(String)” method. However, do note the following text from that method’s documentation:
Notes to Callers
As explained in Best Practices for Using Strings in the .NET Framework, we recommend that you avoid calling string comparison methods that substitute default values and instead call methods that require parameters to be explicitly specified. To determine whether a string begins with a particular substring by using the string comparison rules of the current culture, call the StartsWith(String, StringComparison) method overload with a value of StringComparison.CurrentCulture for its comparisonType parameter.
.NET String class extensions to replace prefix or suffix
Just added the following extension methods to StringExtensions class (of Utils.Extensions namespace) under Utils.Silverlight project at the ClipFlair source code.
public static string ReplacePrefix(
this string s,
string fromPrefix,
string toPrefix,
StringComparison comparisonType = StringComparison.CurrentCulture) { return (s.StartsWith(fromPrefix, comparisonType)) ?
toPrefix + s.Substring(fromPrefix.Length) : s; } public static string ReplacePrefix(
this string s,
string[] fromPrefix,
string toPrefix,
StringComparison comparisonType = StringComparison.CurrentCulture) { foreach (string prefix in fromPrefix) if (s.StartsWith(prefix, comparisonType)) return toPrefix + s.Substring(prefix.Length); return s; } public static string ReplaceSuffix(
this string s,
string fromSuffix,
string toSuffix,
StringComparison comparisonType = StringComparison.CurrentCulture) { return (s.EndsWith(fromSuffix, comparisonType)) ?
s.Substring(0, s.Length - fromSuffix.Length) + toSuffix : s; } public static string ReplaceSuffix(
this string s,
string[] fromSuffix,
string toSuffix,
StringComparison comparisonType = StringComparison.CurrentCulture) { foreach (string suffix in fromSuffix) if (s.EndsWith(suffix, comparisonType)) return s.Substring(0, s.Length - suffix.Length) + toSuffix; return s; }
To use them, you add a reference to Utils.Silverlight project to your own one and then add a using clause for the namespace that hosts a static class with these extension methods (e.g. “using Utils.Extensions;”) and then you can use them on any String at the respective source file. Can even use them on literal strings, since most .NET compilers support Boxing of literals into respective types.
e.g.
s = s.ReplacePrefix("https://", "http://", StringComparison.OrdinalIgnoreCase);
//– converts https:// prefix to http:// ignoring character case
or
s = s.ReplacePrefix(new String[]{"https://", "http://"}, "", StringComparison.OrdinalIgnoreCase);
//– removes https:// or http:// prefix ignoring character case
Update:
I added a default value for the comparisonType method argument to make it optional. I use StringComparison.CurrentCulture as the default value for it (performing a word case-sensitive and culture-sensitive comparison using the current culture), as Microsoft is doing at “String.StartsWith(String)” method. However, do note the following text from that method’s documentation:
Notes to Callers
As explained in Best Practices for Using Strings in the .NET Framework, we recommend that you avoid calling string comparison methods that substitute default values and instead call methods that require parameters to be explicitly specified. To determine whether a string begins with a particular substring by using the string comparison rules of the current culture, call the StartsWith(String, StringComparison) method overload with a value of StringComparison.CurrentCulture for its comparisonType parameter.
IIS FTP login fails after Windows platform update for Server 2008 R2
I had recently enabled FTP access to the ClipFlair Gallery to easy its maintenance during development and after the Windows Server 2008 R2 platform update last night (together with release for Internet Explorer 10), the FTP login stopped working.
To fix it, from a command prompt with administrator rights (Start/Find, type Command and right click the Command Prompt item found to open as administrator), give the command:
netsh advfirewall set global StatefulFtp disable
It’s easy to copy-paste it from here and right-click on the command prompt title bar, then select Edit>Paste (no shortcut key for that unfortunately), then press the ENTER key and it should reply “Ok”.
Had done this before, but seems the platform update re-enabled filtering for Stateful FTP (also note that at http://www.iis.net/learn/publish/using-the-ftp-service/configuring-ftp-firewall-settings-in-iis-7 it seems to erroneously say that you need to use “enble” instead of “disable” when not using SSL).
HowTo: format XML output of DataContractSerializer
based on the other samples posted at StackOverflow on how to format XML created by DataContractSerializer, that use XmlWriter, here’s a version (from ClipFlair source code) that works with streams (and Ionic.Zip library in specific).
It also shows how the code is when you don’t apply formatting (using conditional compilation). Just comment out the #define (prefix it with //) to make it write unformatted XML.
#define WRITE_FORMATTED_XML
using System.Xml;
namespace ClipFlair.Windows
{
public partial class BaseWindow : FloatingWindow
{
//...
#if WRITE_FORMATTED_XML
private static XmlWriterSettings XML_WRITER_SETTINGS =
new XmlWriterSettings() { Indent=true, IndentChars=" "};
#endif
//...
public virtual void SaveOptions(ZipFile zip, string zipFolder = "")
//THIS IS THE CORE SAVING LOGIC
{
if (SavingOptions != null) SavingOptions(this, null); //notify any listeners
View.Busy = true;
try
{
ZipEntry optionsXML =
zip.AddEntry(zipFolder + "/" + View.GetType().FullName + ".options.xml",
new WriteDelegate((entryName, stream) =>
{
DataContractSerializer serializer =
new DataContractSerializer(View.GetType());
//assuming current View isn't null
#if WRITE_FORMATTED_XML
using (XmlWriter writer = XmlWriter.Create(stream, XML_WRITER_SETTINGS))
serializer.WriteObject(writer, View);
#else
serializer.WriteObject(stream, View);
#endif
}));
}
catch (Exception e)
{
MessageBox.Show("ClipFlair options save failed: " + e.Message);
}
finally
{
View.Busy = false; //in any case (error or not) clear the Busy flag
}
if (SavedOptions != null) SavedOptions(this, null); //notify any listeners
}
//...
}
}
Fix: Silverlight Media Framework Player VolumeElement out of sync
I was just adding a storable (persistent) Volume property to the MediaPlayerView class used at ClipFlair’s MediaPlayerWindow (connected to the underlying SMF player’s VolumeLevel property), when I realized that after reloading saved state, the SMF player’s Volume control would show a different value than the value set to it (which I could confirm by flipping the MediaPlayer control and looking at its properties on the backpanel that the ClipFlair app features for each component and for the activity container itself).
It seems to be some bug in the SMF logic or in its default template, since the following fix makes the issue disappear. The trick is that at a descendent class from SMFPlayer (like the MediaPlayer class that ClipFlair’s MediaPlayerWindow uses), one can override the OnApplyTemplate method (a standard method in templated XAML-based controls at Silverlight and WPF) and call the UpdateVolumeElement method shown below.
That method temporarily sets the volume to another value than its current one (this is important, just setting again to the same value would be ignored), then set again the current value to force the VolumeElement control’s UI to update.
//Project: ClipFlair (http://ClipFlair.codeplex.com) //Filename: MediaPlayer.cs //Version: 20130211 using System; using System.Linq; using System.Windows; using System.Windows.Media; using Microsoft.SilverlightMediaFramework.Core; using Microsoft.SilverlightMediaFramework.Core.Media; using Microsoft.SilverlightMediaFramework.Core.Accessibility.Captions; using Microsoft.SilverlightMediaFramework.Plugins.Primitives; namespace ClipFlair.MediaPlayer { public class MediaPlayer : SMFPlayer { public override void OnApplyTemplate() { base.OnApplyTemplate(); //... UpdateVolumeElement(); //patch for SMF bug } protected void UpdateVolumeElement() { //patch for SMF to update VolumeElement UI with any already set VolumeLevel double volume = VolumeLevel; VolumeLevel = (volume == 1) ? 0.9 : 1; VolumeLevel = volume; } //...
Update: While submitting this as a bug to SMF source site on Codeplex it came to me that I could try setting the VolumeElement’s VolumeLevel value directly at ApplyTemplate and indeed it works:
protected void UpdateVolumeElement()
{
//patch for SMF to update VolumeElement UI with any already set VolumeLevel
VolumeElement.VolumeLevel = VolumeLevel;
}
Fix: Visual Studio opens class diagram in XML editor with double click
Recently, to save myself sometime after having renamed some interfaces/classes in the ClipFlair project sourcecode, I right-clicked one of the class diagrams (.cd files) in it at Visual Studio’s “Solution Navigator” (this is an enhanced Solution Explorer addon) and using “Open With…” I opened up the diagrams with the XML editor to do a rename-all operation for the respective class names.
However, after saving the project I found out that from then on, that specific .cd file was opening up as XML file when double-clicked instead of opening up as a Class Diagram in the respective designer pane. Using Open With dialog would open it as a Class Diagram when asked to specifically, but using the checkbox to always open up as Class Diagram wouldn’t help fix the double-click problem for that specific .cd file (others would open up fine as class diagrams, not as XML files, when double-clicked).
I just managed to fix that issue by right clicking the file node in solution navigator’s tree and and excluding that file from the project (not deleting!), then saving the project, closing the solution containg the project and adding the file (via “Add existing file”) again after having reopened the solution. I could also possibly have right clicked selected “Unload project” after saving it and then select to reload it again, think that would have worked too.
Using VisualHG addon for Visual Studio I commited the changes to the Mercurial repository used by ClipFlair on Codeplex, which showed me that the file difference that did the fix was the following in the .csproj project file:
<ItemGroup>
<None Include="Diagrams\Windows.cd" />
- <None Include="Diagrams\Windows.Views.Interfaces.cd">
- <SubType>Designer</SubType>
- </None>
+ <None Include="Diagrams\Windows.Views.Interfaces.cd" />
<None Include="Diagrams\Windows.Views.ViewModels.cd" />
</ItemGroup>
That is instead of that marked-as-bold entry above (marked by the diff tool with – prefix), the line marked with + prefix should be used instead. This is obviously some bug in Visual Studio 2010, it’s nice to know though that you can easily take the project offline and edit the .csproj to fix it (or remove the .cd file, save the project, reload it and add the file again).
Gotcha: Image component not loading remote URLs during debugging
At ClipFlair’s Image component I use the following XAML to make it show an image from a URL that its ViewModel holds at a property named “Source”, of type Uri (URI = Uniform or Universal Resource Identifier in W3C parlance, something like a superset of the old classic URLs).
<Image Name="imgContent"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Source="{Binding Source, Mode=OneWay}"
Stretch="{Binding Stretch, Mode=OneWay}"
>
I’ve had issues in the past with that component not loading an image, a tricky issue was when I had used Mode=TwoWay when data-binding to Source property – that was disastrous, since the Source property expects an ImageSource and just “plays it clever” internally, also accepting a conversion from a Uri. So when doing reverse binding too, you’d end up getting a null value at respective the ViewModel property.
So when it recently started not showing the test image (from a remote URL) that I had been using, I started wondering if it was some regression of that older bug, but couldn’t find some change in the respective code, plus in the Visual Studio XAML designer the component would load and display the remote image fine.
It turned out to be an issue with Silverlight’s security policy regarding cross-site access. The Image control is supposed to be able to load images from any remote URL (without the remote web server needing to have a ClientAccessPolicy.xml file for example to allow it, as is the case with the WebClient class), however I had recently found out that if at your Silverlight project you have selected at the “Debug” tab the “Dynamically generate a test page” option, the Image control wouldn’t load remote images.
What I didn’t know was that even the “Out-of-browser application option there won’t let the Image control load remote images if you don’t select the web project that goes with your Silverlight project (supposing you have them in the same Visual Studio solution), but you happen to select your Silverlight project instead from the dropdown list.
I had changed that option without thinking it might cause an issue while doing other changes in the project. That’s why one should try to do a minimal set of related changes only and test again thoroughly each time (if only they had the time available to do it), so that they can spot such issues early and be able to relate newly introduced bugs to the recent small set of changes, helping to track down the exact change that caused the unwanted behaviour.
Fix: Transform Manager ignoring media files added to watch folders
I’ve been puzzled for some days now with the IIS Transform Manager installation we have at ClipFlair for automating the conversion of media files (for example using Microsoft Expression Encoder) into IIS Smooth Streams.
The watch folder I’ve set up for this task was ignoring some of the media files I was dropping in for no apparent reason (e.g. it was picking up some .MP4 files but not other .MP4 ones).
Eventually I realized that the files it wasn’t picking up didn’t have at their Properties/Security tab access rights for the user account that has been assigned to the Transform Manager service, while the processed files (it keeps them at the “WorkQueue/Finished” subfolder” under the watch folder for the respective job [e.g. “Smooth (VC1)”]) had full access rights for that account.
Obviously by dropping them in the watch folder that had those rights assigned they also got the same rights, but not all the filed did. Maybe it is some Windows Server 2008 R2 bug when dropping multiple files together into a folder, not sure though. Adding the needed rights to each of those files, Transform Manager watch folder task immediately pulled them for processing (and soon put them into the “WorkQueue/Running”)
Another thing I noted was that at the Watch Folder task’s (say the “Video files to VC-1 Smooth Streams” ) “Scheduler” tab, at “Concurrent Jobs”, the default setting was set to 1. If you control how many files are placed in the watch folder (e.g. users aren’t uploading files there themselves) you can even check the value “Unlimited” there to process all the dropped files in parallel.
Can’t step-through Silverlight file dialogs with Visual Studio debugger
While stepping through “ShowDialog()” method of OpenFileDialog with Visual Studio 2010 debugger, at the Silverlight code pictured below (for loading a ClipFlair window’s stored options), I got a “Dialogs must be user-initiated” exception. Same behaviour will be shown with SaveFileDialog too, every time you try to step through the “ShowDialog()” method.
This is because of Silverlight’s security model, which doesn’t allow source code to programmatically show a file dialog when an app is running in its default security sandbox (app is not signed with certificate and user hasn’t given consent for it to run in elevated rights mode), unless that code is called from an event handler that handles some user action on the UI (e.g. some button has been clicked by the user).
Obviously, when stepping through with the debugger it loses the user-initiated-action context somehow and considers the debugger as the initiator of the action, thus not allowing the file dialog to be shown when you try to step-through the “ShowDialog()” method of OpenFileDialog or SaveFileDialog.
The only solution I can suggest is to put a breakpoint right after the “ShowDialog()” returns (e.g. at “using” statement in the code below). If you place a breakpoint at any source code row above or at the “ShowDialog” inside the event handler method (“btnLoad_Click” in the code below) it will fail when the debugger tries to go through the “ShowDialog” method, even if you press “Run” after that breakpoint fires to continue.