MSbuild Task FileUpdate to replace content in text files

I wanted to replace some strings in files using my deployment MSbuild script.

I've noticed that MSBuild Community Tasks Project has RegexReplace task.

But when I've looked in documentation 

(By the way, it will be good if Reference help will be available online, not only from download)

I've realized that the task is applicable for strings(e.g file names) not to content within a file.

Almost accidently in one of the posts i've found a reference to FileUpdate
task, that support Regex and does content replacements within a file.

The following examle (from downloaded help) search for a version number and update the revision.

 
            <FileUpdate Files="version.txt"
                Regex="(\d+)\.(\d+)\.(\d+)\.(\d+)"
                ReplacementText="$1.$2.$3.123" />


 

MSDN documentation -methods that have corresponding operators shouldn't be called directly

In our old code I'vew noticed a few examples of code like the following:
 MyFortune = Decimal.Add(MyFortune, .01m);
I was wandered, why they didn't use "+" sign, and didn't find any explanation.
The MSDN reference documentation doesn't explain, that methods like Add, Subtract,Multiply,Divide usually should not be called explicitely. 
Instead of using Add method it's simpler to use + sign ( Addition Operator ).
E.g.
    MyFortune = Decimal.Add(MyFortune, .01m);
can be rewritten as 
    MyFortune += .01m;

Comment like this should be added to all methods, that have corresponding operators.

I've posted a suggestion to MS Feedback


DNN ability to 'Publish Web Site'

3 years ago I've posted a workaround regarding DNN
BUG App_GlobalResources and 'Publish Web Site' in VS2005 
 
The issue is still not resolved and I recently received an email

I would like to thank you a lot for your post on a DNN forum which explain how to use DNN in precompiled mode.

( AppGlobalRessources...... )

T H A N K S !!!!!!!!!!

 I am glad that the workaround is still useful, but DNN team should create a new version(even with breaking changes)

Scheduled Tasks tool should validate username/password combination

Schedule Tasks in Windows  required to specify username and password. However it doesn't verify that the combination is correct.

Scheduled Tasks tool should have an option to verify username/password combination and this validation should be forced when user saved(clicked OK) the task.

I've noticed the issue on Windows 2003 server. Not sure, is it implemented on newer windows versions.

Do not check-in DEBUG specific code.

We are using .Net Remoting to interact beteeen client and back end server. I needed to call a method from services class.
For debugging purposes I decided to create the class directly. It was easier to debug without starting extra back-end process.
The code was like the following:

IMyServices services = (IMyServices)RemotingHelper.GetObject(typeof(IMyServices));
#if DEBUG
    services = new MyServices();
#endif
// Process the task
services.ProcessItems(ItemsCollection); 

During the development I checked that the method done the required processing and changed the parameter object as expected.

And I've checked in the code, assuming that in Release mode the application will work the same way just by instantiating proxy instead of full object.
However in Release mode changes in parameter inside calling method were not returned back.
Of course, If parameter is serializable, it is passed by value. and correct implementation will use return value

 ItemsCollection = services.ProcessItems(ItemsCollection);

But more general recommendation before check-in remove/comment-out any DEBUG specific shortcuts and test the code  as it will be in production.



Call eventTimer_Elapsed method asyncronoulsy OnStart of Windows Service

We have   eventTimer in Windows Service  (similar as described in  Timer Objects in Windows Services with C#.NET 
and Using Timers in a Windows Service) to run the  relatively long-running process repeatedly.
 
NOTE: It is NOT a good idea to Use a Windows Service just to run a scheduled process, but I have to maintain a legacy application, that was written as a Windows Service .
 
The process called each time when eventTimer_Elapsed. But I want to run it immediately(not to wait until timer will elapsed)  when service started or Continued.
However I wanted to call it asynchronously from OnStart method, because otherwise Start command seems to hang until process is finished.
Thanks to asyncronous calls for delegates, I 've created a function to invoke eventTimer_Elapsed from any place asyncronously and my service has the following methods:
 
private void BeginInvokeElapsedEvent(object sender, ElapsedEventArgs e)
{// Initialize the first update asynchronously
ElapsedEventHandler dlgt = eventTimer_Elapsed;

dlgt.BeginInvoke(sender,e);

}
protected override void OnContinue() 
{
 this.eventTimer.Start();
BeginInvokeElapsedEvent(this,null);// MyLongProcess();
base.OnContinue ();

}

protected override void OnStart(string[] args)
{

Initialise();

// Initialize the first update asynchronously// MyLongProcess();
BeginInvokeElapsedEvent(this,null);

}

private void eventTimer_Elapsed(object sender, ElapsedEventArgs e)
{

MyLongProcess();

}

Related links:Comparing the Timer Classes in the .NET Framework Class Library

LINQ to XML -How to use XPass for elements selection

I am just starting to work with LINQ to XML and tried to find child document similar to the following:
 xml.Element("client/child");
But it throw exception
System.Xml.XmlException: The '/' character, hexadecimal value 0x2F, cannot be included in a name.
The reason is that LINQ to XML doesn't directly support XPAth
Fortunately there are extensions, that allow to use XPath for XElement search/selection.

using System.Xml.XPath;

and then

var clients = xml.XPathSelectElements ( "client/child" );

Consider, if required ,an XPathSelectElements overload  with namespace management.

Note, that XPath extensions are actually backward compatibility feature, and Microsoft recommends to use native XElement methods, such as Descendants ,Elements,Element etc.  See Comparison of XPath and LINQ to XML
 However K. Scott Allen  prefers to mix LINQ and XPath  to have concise code.

See also Concepts LINQ to XML for XPath Users

Useful tip:where clause and "Possible System.NullReferenceException"

Misleading error message when NullReferenceException thrown within Comparer

We've got an error messgae from custom comparer:
IComparer (or the IComparable methods it relies upon) did not
return zero when Array.Sort called x. CompareTo(x).
 
After investigation it was found, that the error was caused by NullReferenceException,
 thrown within Comparer.
I've suggested to Microsoft , that the actual NullReferenceException error message should be shown instead of this misleading one.
See also similar feedback

 

EnsureDirectoryExists helper function

Below is a simple EnsureDirectoryExists helper function:
public static void EnsureDirectoryExists(string targetPath)
        {
            string dir = Path.GetDirectoryName(targetPath);
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
        }

Use HashSet instead of "seen" Hashtable.

In our code (originally created in .Net 1.1)  there are a few examples of "seen" Hashtable pattern
 
Hashtable seen = new Hashtable();
for (int i = 0; i < nCount; i++)
{
    if (seen[key] == null)
    {
        //Do the changes
        seen.Add(key, key);
    }
}
 
It's better to use type-safe HashSet:
 
HashSet<string> seen = new HashSet<string>();
for (int i = 0; i < nCount; i++)
{
    if (!seen.Contains(key))
    {
        //Do the changes
        seen.Add(key);
    }
}

Don't Repeat Yourself(DRY principle) when modifying existing function

If there is an existing  non-trivial function and you need to change it , do NOT copy and paste it , but modify to satisfy new requirements.
You may be need to split a big function into small ones and call them in different order or with different parameters.
Often you need just to add extra parameter to the function and have if-else branches depending on a new parameter.
In some cases new change is actually a fix of the problem, that applicable to all usages of the function.
Remember that "Copy and Paste" is NOT a good way of code re-use.
 
I also strongly recommend to read Exploring Smelly Code article to avoid other anti-patterns.
 

Typed DataTable's base class in VS008

I have a typed Dataset, generated by VS Designer. Resently I've added a new column to one of the tables, and suddently in different DLLs where the dataset was used, I've started to get

Error 22 The type 'System.Data.TypedTableBase`1<T0>' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

 

Apparently VS 2008 changed the base class for Typed DataTables 

3.5 : public partial class SubusersDataTable : global::System.Data.TypedTableBase<SubusersRow> {

2.0: public partial class SubusersDataTable : global::System.Data.DataTable, global::System.Collections.IEnumerable {

 and you need to change all dependant assemblies to

target 3.5 framework (if not done yet) and

add a reference to assembly 'System.Data.DataSetExtensions, Version=3.5.0.0 

 

More details about the change from http://blogs.msdn.com/vbteam/archive/2008/05/14/how-linq-to-dataset-works-in-vb-jonathan-aneja.aspx

Note that for strongly-typed Datasets you don’t need to call AsEnumerable, as they inherit from TypedTableBase(Of T) which implements IEnumerable.  This is a new type in VS2008; in VS2005 the Dataset Designer would generate code that inherited from DataTable and then explicitly implemented IEnumerable itself.

 

Safe Save DateTime to SQl Database.

When I tried to save DateTime data to SQL database, I've got 
SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
I've had to create a function
object SafeSqlDateTime(DateTime dtValue)
{
object theValue = dtValue;
if (dtValue <(DateTime) SqlDateTime.MinValue) // January 1, 1753.
{
   theValue =
null;
}
return theValue;
For opposite SqlDateTime to DateTime Conversion see
http://msdn.microsoft.com/en-us/library/aa326475(VS.71).aspx
 

Workflow Activities should be referred by sender object or e.Activity, not by activity property name

In Windows Workflow I had a Replicator Activity inside While Activity. In Replicator  _Initialized event handler I've set the InitialChildData property of the activity with the list of my objects, but Replicator  didn't invoke  any _ChildInitialized event , but went directly to _Completed event (similar problem was reported in the thread ReplicatorActivity shows all children complete when they aren't ). I tried to change a few things without success.It was also confusing that even in Initialized AllChildrenComplete property was true. I compared my code with exampe from excellent WF Tutorial: Using the Replicator for Windows Workflow Foundation, but didn't find any essential differences.
 
Finally WF Serialization Part One and a half article pointed me to Spawned Contexts - Replicator, While, State, EventHandlers, and CAG , that exlpained that I've incorrectly updated data of a template activity instead of instance activity.
Important extracts from  the article:
 
 If you want to avoid issues, learn to access activity properties in a context safe way (using the sender object or  e.Activity) so that you do it right when it counts. 
// WRONG CODE
this.delayActivity1.TimeoutDuration = TimeSpan.FromSeconds(iterationCount);
// RIGHT CODE
((DelayActivity)sender).TimeoutDuration = TimeSpan.FromSeconds(iterationCount);

// RIGHT CODE
CallExternalMethodActiivty act = e.Activity.GetActivityByName("createTask1", true) as CallExternalMethodActivity;
act.ParameterBindings["userName"].Value = e.InstanceData;

Use sender or e.Activity instead of this.  e.Activity is the clone of the replicator's template (Sequence(2-4)).  Second, we have passed the parameter true to GetActivityByName.  This tells the method to look only in the context of the activity on which it was called.  This keeps the method from walking into other parts of the tree and returning the RootContext instance.

 The issue also described in "Pro WF" By Bruce Bukovics access activities in a context safe way   section.

 I hope that Microsoft will change the syntax of event handlers to separate workflow templates and instances to avoid these not-intuitive errors.


.Net Remoting clent proxy error in debugger inspection

I am using .Net Remoting and tried to debug call from client proxy. It didn't allow me to step into(whick is actually normal) and Debugger inspection showed me that Identity property has an exception:
 

  Identity System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Runtime.Remoting.RemotingException: Permission denied: cannot call non-public or static methods remotely.

Server stack trace:
   at System.Runtime.Remoting.Channels.ChannelServices.DispatchMessage(IServerChannelSinkStack sinkStack, IMessage msg, IMessage& replyMsg)

Exception rethrown at [0]:
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at System.MarshalByRefObject.get_Identity()
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
   at Microsoft.Office.Tools.Debugger.Tools.TryCreateDebuggerItem(MemberInfo member, Object target, __Item& item) System.Reflection.TargetInvocationException

 
I've decided that there is an error and tried to find the solution. Similar issues (without good explanation) are:
 
Fortunately this debugger message can be ignored, and my call to remoting service worked as expected.

«July»
SunMonTueWedThuFriSat
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678