TFS Activity for InvokeProcess (without wait) - tfs

I see lots of posts for waiting on the return value of various activities, but in this case, I'd like to kick off an activity and then not wait. I just want to copy a directory over a (very) slow network, so I'd prefer not to create another activity or use a batch script for this. Anyone done this? Is there a clean way? I could cobble something together, but I'm trying to keep this as vanilla as possible.

I don't think that something out of the box is available for you to use. One way to proceed is to organize an "Invoke Process" that invokes another service that does the actual copying. So from within Build you advance and let the invoked entity (that is out of scope in terms of TFS build) do the actual activity. This does come with certain deficiencies, the more important being that you won't ever know in your build-logs if this succeeded or failed.Another option is to use the Parallel activity (it's in the Toolbox under "Control Flow" - System.Activities.Statements.Parallel). This is not quite like what you need (kick & forget), still it could allow you to do other stuff while your copy happens.

Here is simple custom activity that will create new process:
[BuildActivity (HostEnvironmentOption.All)]
public sealed class InvokeProcessAsync : CodeActivity
{
[RequiredArgument]
public InArgument<string> FileName { get; set; }
public InArgument<string> Arguments { get; set; }
public InArgument<string> WorkingDirectory { get; set; }
public InArgument<IDictionary<string, string>> EnvironmentVariables { get; set; }
protected override void Execute (CodeActivityContext context)
{
context.DublicateOperationsLogsToBuildOutput ();
var psi = new ProcessStartInfo
{
FileName = context.GetValue (this.FileName),
Arguments = context.GetValue (this.Arguments),
WorkingDirectory = context.GetValue (this.WorkingDirectory)
};
var env_vars = context.GetValue (this.EnvironmentVariables);
if (env_vars != null)
{
foreach (var v in env_vars)
psi.EnvironmentVariables.Add (v.Key, v.Value);
}
Process.Start (psi);
}
}

CopyDirectory activity from the Build.Workflow assembly is what you need.

Related

Dependency Injection and data models

I'm new to dependency injection but fast becoming a big fan. However I can't seem to find anything that satisfactorily describes how to deal with objects at run time which are not injected from a container. I'll refer to same as data objects.
Consider the following, (forgive me if the following shows I've completely missed the point of DI):-
In the old days I would code an object as follows: -
public class Person
{
public string Name { get; set; }
public string EmailAddress { get; set; }
public void DoSomething(params string[] paremeters)
{
//code to do something with this person using parameters
}
public void DoSomethingElse()
{
//code to do something else with this person
}
}
Now with DI I might do the following: -
public class Person
{
public string Name { get; set; }
public string EmailAddress { get; set; }
}
public interface IPersonService
{
void DoSomething(Person person, params string[] paremeters);
void DoSomethingElse(Person person);
}
public class PersonService : IPersonService
{
public void DoSomething(Person person, params string[] paremeters)
{
//code to do something with this person using parameters
}
public void DoSomethingElse(Person person)
{
//code to do something else with this person
}
}
And the IPersonService service would be 'injected' through constructors into any processes that needed it. The problem is that it feels wrong having to add a Person parameter to every procedure and method in the PersonService but no alternatives seem to work any better.
For example I could use something like
Person _person;
void Configure(Person person)
{
_person = person
}
..in all my injected services which needed transient data, but then you run into state problems and all such services need to be transient. Again not happy with that.
In this example the person might come from a database, a screen form, a file, have been selected from a list in a directory or anywhere else.
I am aware that I could inject my data using a data repository (class to access the data and all the CRUD stuff) and indeed I have every intention of doing that but that still doesn't solve the problem of how I tell the service, in this case, which person to access unless of course I add a procedure into the service which includes a parameter for the identity of the person and then use the repository to go and fetch the person... but that then works just like the Initialise approach which results in State problems. It also relies on remembering to call the procedure in the service to configure the data.
My question is, what's the best practise here? Please keep it simple.
Many thanks

Constructor not created in proxy class with Add Service Reference

I have created a web service with ServiceStack which returns List<SyncUserDTO>.
It has more properties, but I simplified it to one field, Timestamp.
[DataContract]
public class SyncUserDTO
{
public SyncUserDTO()
{
Timestamp = new TimestampDTO();
}
[DataMember(Order = 1)]
public TimestampDTO Timestamp { get; set; }
}
[DataContract]
public class TimestampDTO
{
[DataMember]
public bool DataValid { get; set; }
[DataMember]
public DateTime? Value { get; set; }
}
The service seems to work perfectly (with other tests), but when I create a client console application and Add Service Reference, the SyncUserDTO does not have the constructor, meaning this doesn't work:
static void SendUsersServiceReference()
{
var users = new List<SyncUserDTO>();
for (var i = 0; i < 5; i++)
{
var user = new SyncUserDTO();
user.Timestamp.Value = DateTime.Now; // NullReferenceException,
user.Timestamp.DataValid = true; // as Timestamp is null
}
}
When pressing F12 on SyncUserDTO, I can't seem to find any Constructor method in Reference.cs, explaining why the above doesn't work.
But why is the constructor not created in my proxy classes in the client application?
I need to do the "construction" myself in the client, and then it works:
var user = new SyncUserDTO() { Timestamp = new TimestampDTO() };
Of cause, I don't want the people who consumes my service to have to create this themselves. They should really note care about the underlying TimestampDTO. The constructor should do this.
Btw, I searched Google and SO for terms like "Constructor not created in proxy class with Add Service Reference" with and without "ServiceStack", no results to aid me in this quest...
Pps. Demis (ServiceStack), if you're reading this, yes SOAP is on the way out, REST is the new black - but I want to support both, which it seems like ServiceStack does, which is really great. I love ServiceStack :D
try to instanciate your property by the time you are going to access it, I know that´s a workaround but it could be convenient in your scenario.
private TimestampDTO _timestamp;
public TimestampDTO Timestamp
{
get
{
if(_timestamp==null) _timestamp=new TimestampDTO();
return _timestamp;
}
set
{
_Timestamp=value;
}
}
This is my solution (for now):
I created a new service method in my service, where the client gets a new UserDTO complete with all fields. This way, the constructor is run on the server. I bet I have quite a performance hit this way, but it doesn't matter that much (now...).
Service DTO's:
[DataContract]
public class ReturnNewEmptyUser : IReturn<ReturnNewEmptyUserResponse> {}
[DataContract]
public class ReturnNewEmptyUserResponse
{
[DataMember]
public SyncUserDTO User { get; set; }
}
The Service:
public class SyncService : Service
{
public ReturnNewEmptyUserResponse Any(ReturnNewEmptyUser request)
{
var user = new ReturnNewEmptyUserResponse { User = new SyncUserDTO() };
return user;
}
}
On the client:
static void SendUsersServiceReference()
{
var webservice = new ServiceReference1.SyncReplyClient();
var users = new List<User>();
for (var i = 0; i < 5; i++)
{
var userResponse = webservice.ReturnNewEmptyUser(new ReturnNewEmptyUser());
var user = userResponse.User;
user.Timestamp.Value = DateTime.Now;
user.Timestamp.DataValid = true;
// Continue with field population...
users.Add(user);
}
// Send users with webservice method
// ...
}
We're wondering if it is a bad way to expose the fields this way. It is nice, because the client can use autocomplete and know exactly the types used - but is it better to force the client to create an XML/JSON in a specific format.
This should be in another question - this question I guess has been answered: Add service reference/proxy classes does not contain methods (incl. constructors for types), only types. If you really need the constructor, have it run and then exposed on the server and then consume it from the client. Like a factory-thing, as Adam wrote here: Class constructor (from C# web service) won't auto-implement properties in C# MVC
Btw - is there any security issues with this design? User is logged in via url-credentials (should probably be header authentication), only a few systems has access to it.
A proxy class does not keep implementation details, like a constructor. It is just a DTO. This can only be done if you share the classes, through a shared project.
Think about that servicestack is just telling the client which properties it needs, and their type.. the implementation is up to the client.

Looking for a build activity which breaks a build when new warnings are introduced

We're attempting to clean up a big bunch of brown field code, while at the same time a team is adding new functionality. We'd like to make sure changed and new code is cleaned from any compiler/code analysis or other warnings, but there's too many of them to begin by cleaning up the current solution.
We're using TFS 2010.
So the following was proposed:
Write/select a build activity which compares the list of warnings in the build against the lines of code that changed with that check-in.
If the warning provides a line number, and that line number was changed, fail the build.
I understand this will not find all new warnings and things introduced in other parts of the code will not be flagged, but it's at least something.
Another option that was proposed:
Compare the list of warnings of the previous known good build against the list of this build. If there are new warnings (track on file name level), fail the build.
Any known Actions out there that might provide said functionality?
Any similar Actions that can act on Code Coverage reports?
This following activity is just a basic approach, that returns false if your current build has less or equal warnings than your last build and true if they have risen.Another activity that can locate new warnings and/or present with their location in code would clearly be superior, yet I thought this might be an interesting startpoint:
using System;
using System.Activities;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Build.Workflow.Activities;
namespace CheckWarnings
{
[BuildActivity(HostEnvironmentOption.Agent)]
public sealed class CheckWarnings : CodeActivity<bool>
{
[RequiredArgument]
public InArgument<IBuildDetail> CurrentBuild { get; set; } //buildDetail
public InArgument<string> Configuration { get; set; } //platformConfiguration.Configuration
public InArgument<string> Platform { get; set; } //platformConfiguration.Platform
protected override bool Execute(CodeActivityContext context)
{
IBuildDetail currentBuildDetail = context.GetValue(CurrentBuild);
string currentConfiguration = context.GetValue(Configuration);
string currentPlatform = context.GetValue(Platform);
Uri lastKnownGoodBuildUri = currentBuildDetail.BuildDefinition.LastGoodBuildUri;
IBuildDetail lastKnownGoodBuild = currentBuildDetail.BuildServer.GetBuild(lastKnownGoodBuildUri);
int numOfCurrentWarnings = GetNumberOfWarnings(currentBuildDetail, currentConfiguration, currentPlatform);
context.TrackBuildMessage("Current compile presents " + numOfCurrentWarnings + " warnings.", BuildMessageImportance.Normal);
int numOfLastGoodBuildWarnings = GetNumberOfWarnings(lastKnownGoodBuild, currentConfiguration,
currentPlatform);
context.TrackBuildMessage("Equivalent last good build compile presents " + numOfLastGoodBuildWarnings + " warnings.", BuildMessageImportance.Normal);
if (numOfLastGoodBuildWarnings < numOfCurrentWarnings)
{
return true;
}
return false;
}
private static int GetNumberOfWarnings(IBuildDetail buildDetail, string configuration, string platform)
{
var buildInformationNodes =
buildDetail.Information.GetNodesByType("ConfigurationSummary");
foreach (var buildInformationNode in buildInformationNodes)
{
string localPlatform, numOfWarnings;
string localConfiguration = localPlatform = numOfWarnings = "";
foreach (var field in buildInformationNode.Fields)
{
if (field.Key == "Flavor")
{
localConfiguration = field.Value;
}
if (field.Key == "Platform")
{
localPlatform = field.Value;
}
if (field.Key == "TotalCompilationWarnings")
{
numOfWarnings = field.Value;
}
}
if(localConfiguration == configuration && localPlatform == platform)
{
return Convert.ToInt32((numOfWarnings));
}
}
return 0;
}
}
}
Note that this activity doesn't provide with exception handling and should further be refined, in case your build definitions build more than one solutions.It takes three input args (buildDetail, platformConfiguration.Configuration and platformConfiguration.Platform) and should be placed directly after the Run MSBuild activity.

MVVM Light - Unable to update parent view from child - nested edit

My situation is slightly different than from other posts and I was not able to solve it with the other trhreads. So that why I ask.
I have a class that is obtained from deserializing an XML like:
<?xml version="1.0" encoding="UTF-8"?>
<node>
<leaf>
<name>node 1</name>
<text>text 1</text>
<url>url 1</url>
</leaf>
<leaf>
<name>node 2</name>
<text>text 2</text>
<url>url 2</url>
</leaf>
</node>
so the class is:
[XmlRoot("node")]
public class csNodeList
{
public csNodeList()
{
Leaf = new csLeafCollection();
}
[XmlElement("leaf")]
public csLeafCollection Leaf
{
get;
set;
}
}
public class csLeaf
{
public csLeaf()
{
Name ="";
Description = "";
Address = "";
}
[XmlElement("name")]
public string Name
{
get;
set;
}
[XmlElement("text")]
public string Description
{
get;
set;
}
[XmlElement("url")]
public string Address
{
get;
set;
}
}
public class csLeafCollection : System.Collections.ObjectModel.ObservableCollection<csLeaf>
{
}
Then I have 2 Views, one to show all the leafs and one to edit one leaf. I've implemented commit and rollback so I use messaging back and forth to pass the new values and I store the old ones.
To do so I copy the objects a a backup variable and then I modify the ones associated via binding to the XAML view, in this way (in theory) any change to the ViewModel data should be reflected.
Also is better because if I commit the changes I just discard the backup variables (this is 90% of the times) and if I need to roll back I copy back from the backup variables.
MainView:
public const string listPropertyName = "list";
private csNodeList _list = new csNodeList();
public csNodeList list
{
get
{
return _list;
}
set
{
Set(listPropertyName, ref _list, value, false);
}
}
Using the message I send back the new values of a node and I put them in the correct position:
private void DoSomething(csMessage message)
{
csMessage rmessage;
if (message != null)
{
switch (message.destination)
{
case csMessage.e2MessageDest.updateNode:
//_editP should be fine.
list.Leaf[list.Leaf.IndexOf(_editP)].Name = ((csLeaf)message.payload).Name;
list.Leaf[list.Leaf.IndexOf(_editP)].Text= ((csLeaf)message.payload).Text;
list.Leaf[list.Leaf.IndexOf(_editP)].Address = ((csLeaf)message.payload).Address;
RaisePropertyChanged(listPropertyName , null, _list, true);
break;
}
}
}
The code is executed correctly and the item is changed.
BUT the RaisePropertyChanged is ignored. I've tried even just the one with the listPropertyName without any change.
If I save the changes exit from the app and get back I see the new value correctly stored
Can you please help me?
Thanks,
Massimo
The reason why your RaisePropertyChanged is ignored is hat yor Leaf class des not implement INotifyOropertyChanged. Commonly the model is wrapped into a view model which then implements INotifyPropertyChanged to notify the view hat something has happened.
However, you also can implement INotifyPropertyChanged on the model class directly. To implement INotifyPropertyChanged each property has to raise the propty changed event.
public string Property {
get { ... }
set {
if (_propertyField == value)
return;
_propertyField = value;
RaisePropertyChanged("Property");
}
}
The code assumes hat there is a method RaisePropertyChanged which actually taises the PropertyChangedEvent.
Thank you everyone for the help.
Investigating your suggestion I've found a slightly different solution; as you correctly said the issue is that the leaf fields are not "observable" so they do not generate a notification event.
I've noticed that if I add or Delete a profile the binding is updated.
So what I've decided to do is not to edit directly the leafs but to replace the node.
What I do not like is that I have to create a node to replace the old one and this allocates a little bit more memory... but for small data like the one I have it can work without any major impact on the app performance/memory foot print.
Here is what I do:
csLeaf _leaf = new slLeaf();
_leaf.Name = ((csLeaf)message.payload).Name;
_leaf.Text= ((csLeaf)message.payload).Text;
_leaf.URL = ((csLeaf)message.payload).Address;
list.Leaf[list.Leaf.IndexOf(_editP)] = _leaf;
To optimized readabilty of code I've enhanced it adding a constructor with 3 parameters so that the code can be:
csLeaf _leaf = new slLeaf(((csLeaf)message.payload).Name, ((csLeaf)message.payload).Text, ((csLeaf)message.payload).Address);
list.Leaf[list.Leaf.IndexOf(_editP)] = _leaf;
The constructor is:
public csLeaf(string _name, string _description, string _address)
{
Name = _name;
Description = _description;
Address = _address;
}

Custom build activity - display changes made since previous commit

Using a custom activity inside the build template, is there a way to enumerate through the changes made since the previous build?
I plan on eventually compiling a list of changes so when the build is triggered an E-mail is sent displaying information on the build as well as the changes made.
Any information or links would be great.
Thanks
Edit
Would something similar to this work, if I passed the changeset into my custom activity?
public sealed class ChangeSetActivity : CodeActivity
{
// Define an activity input argument of type string
public InArgument<string> Text { get; set; }
public InArgument<IBuildDetail> currentBuild { get; set; }
public InArgument<List<IChangesetSummary>> changes { get; set; }
public OutArgument<string> changeSet { get; set; }
// If your activity returns a value, derive from CodeActivity<TResult>
// and return the value from the Execute method.
protected override void Execute(CodeActivityContext context)
{
// Obtain the runtime value of the Text input argument
string text = context.GetValue(this.Text);
string str = "";
foreach (IChangesetSummary c in changes.Get(context))
{
str = string.Format("User - {0} Comment - {1}", c.CheckedInBy, c.Comment);
}
context.SetValue<string>(this.changeSet, str);
}
}
Obviously this is very basic stuff at the minute, just to get it working.
Edit
Found this:
http://blogs.msdn.com/b/codejunkie/archive/2010/09/02/custom-build-activity-for-tfs-2010-to-send-email-with-build-details-part-1.aspx
In the DefaultTemplate there is at the end an activity called AssociateChangesetsAndWorkitems which calculates the changes and stores the information in the associatedChangesets variable. You can use this information to sent your email.

Resources