Doing FTP in .Net is not as hard as you may imagine. There is a very simple way and a bit advanced way. Simple way is using System.Net.WebClient class and its UploadFile method. Advanced way includes using System.Net.FtpWebRequest and System.Net.FtpWebResponse classes. Using them you can do ordinary FTP operations like ListDirectory, UploadFile, DeleteFile, etc. For an example see following code. More information is available from here.
public void DeleteFile(string remotePath)
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(remotePath);
request.Credentials = new NetworkCredential("user name", "password");
request.Method = WebRequestMethods.Ftp.DeleteFile;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
If you have added some new Activity or CodeActivity to your build process template but you don’t want to edit template process each time you want modify properties of Activity or CodeActivity, you must add that parameter to “Build process parameters” list of your desired build definition. By doing this, there is no need to modify template process and check-in back it each time.
Jason has described this and has showed how you can do it by editing XAML file directly. But if you are searching for an easier way, follow these steps:
1. Open build process template.
2. Open Arguments tab at the bottom-left corner of the screen.
3. Add your parameters as “In” arguments.
4. Pass value of these arguments to properties of desired build/workflow activities.
5. Save and check-in template process.
6. Open up Build Definition that uses this template process.
7. Go to Process tab and navigate to Misc section. You will see your added arguments there, that are added as “Build process parameters”.
8. Fill your values there to be used by TFS Build.
After reading Jim Lamb’s guide for creating a custom workflow activity for TFS Build 2010, I created a project to create my own custom workflow activity too, by following Jim’s guides line by line. At the end, despite my correct custom activity, when I tried to use that in a typical template process by dragging it onto the workflow I just saw a deny symbol and couldn’t put my activity on that workflow.
After so many verifications of my custom activity and so many googling, I decided to add my activity by editing XAML file directly in notepad. Unfortunately when loaded the workflow in the Visual Studio again, a red label with message “Activity could not be loaded because of errors in the XAML.” was showing instead of my activity. So googled again and found Ewald Hofman’s solution. Based on his guides I installed my assembly in GAC and the red error message label disappeared. I was having still 2 more problems. First, Jim’s sample code was working with no problem, but my activity needed registration in GAC. Second, despite of disappearing red label, I was still unable to drag my activity to workflows, I was forced to edit XAML file directly.
After a whole challenging day, I realized that Jim’s sample assembly exists in C:Program Files (x86)Microsoft Visual Studio 10.0Common7IDEPrivateAssemblies previously! I don’t know how Jim’s ActivityPack has gone to that location but I know when I copied my custom activity’s assembly to that location, my 2 problem solved too. So I could use Visual Studio designer to drag my custom workflow activity into any workflow or template process I want.
I was used to use entlib for logging. But as I’m in favour of open source and because I am using NHibernate and Castle ActiveRecord in my applications, decided to use log4net instead. So found a good article about it, and enabled it for my application. But the problem was a very huge log file was producing because of verbose logs from NHibernate.
I’ve been heard that log4net uses hierarchical loggers but did not have a good understanding of it. I was thinking that using hierarchical loggers I can omit NHibernate’s logs and instead show my application’s logs. My bad assumption about hierarchical loggers was that they should be defined in app.config/web.config as nested. Obviously this assumption was wrong. Hierarchical logger in log4net means that you define a root and define all loggers inside it directly. Hierarchy then is understood of “name” attribute of “logger” node. This just acts a C# namespaces. For example you can have “NHibernate” and “NHibernate.SQL”. The second one is a child of the first.
Following guides in this, this, this, this and this link helped me to build my own config that works greatly in my application:
value="%d [%t] %-5p %c [%x] - %m%n" />
value="%d [%t] %-5p %c [%x] - %m%n" />
If you ever has need to customize build process in Team Foundation Build 2010, you may noticed that there is several ways to do it while each way is suitable for a specific range of requirements:
1. Running external tools like batch files or ftp.exe or MSBuild Community Tasks via InvokeProcess or via MSBuild Activity.
2. Invoke .Net classes and methods like System.IO.File.Delete() via InvokeMethod.
3. Creating your own custom workflow activity for TFS Build 2010.
For our specific need that is synchronizing a remote server via FTP, none of first 2 ways is suitable. In first way, running external programs, this is very hard to synchronize a whole remote directory and its sub-directories just via ftp.exe and a bunch of batch file commands like FOR. In addition, this may impose dependency to external tools in the server.
In the second way, running .Net classes and methods, we have to create our own ftp utility or use third party tools like ftp.exe or MSBuild Community Tasks. In addition this causes using intensive usage of TF Build activities that’s not easy to copy to new Team Foundation builds in new projects.
Third and last way, creating your own activity is harder to implement but has many advantages over other ways including:
1. High flexibility because this is entirely written by yourself.
2. Maintaining is easier because all of your work is kept in a single Visual Studio project.
3. It is easier to deploy it in new team builds because it is simply just one single workflow activity.
4. It is easier to configure. You configure it via its arguments and variables. No need to modify template process itself.
I’m using log4net for logging in my ASP.NET application. This web site is based on .Net framework 3.5 and is installed on IIS 7.5 and Windows Server 2008 R2 in a 64 bit machine. Logging was working greatly when I was running application from Visual Studio 2010’s internal web server, but was not working at all when run from IIS.
First thing that I thought about was permission. So I grant full access to network service with the folder containing application: “c:inetpubwwwrootmyapp”. But this didn’t work and no log file generated. As I’m new to Windows Server 2008, I tried to grant full permission to all users that I knew: IUSR, local service, aspnet, IIS_IUSRS, Everyone, etc. But still nothing was working. A question in SO caused me to think this is because of trust level, so I set my application’s trust level to full. But still nothing was working. Another question in serverfault.com caused me to think the problem root is that Windows Server 2008 is using a new user for IIS. So I tried to use icacls to add ApplicationPoolIdentity to permission list. After it, I tried to change Identity of DefaultAppPool to Network Service. But none of this two solutions solved my problem.
Some people have been recommending to enabling internal logging of log4net to detect original problem. And yes, this showed me what was the problem:
log4net: XmlConfigurator: config file [C:inetpubwwwrootlog4net.config] not found. Configuration unchanged.
After some investigations, root cause was detected. It was due to incorrect use of Server.MapPath. I was forgotten to add a tilde mark in beginning of log4net.config’s path. When I used Server.MapPath as follow, all headaches have suddenly disappeared and my log file appeared and get working as I was desiring:
A wrong path has been causing log4net to search c:inetpubwwwroot for log4net.config not my application’s path at c:inetpubwwwrootmyapp. All this nightmare was because of my own mistake not Windows, IIS or .Net!
We have a Visual Studio solution that uses some external assemblies coming from third parties. This solution resides in TFS 2010 version control. We have configured Team Foundation Build to do automatic builds of the solution. As you know you should put any external assemblies in TFS Version Control to do a proper build without any build breaks. So we did same. Whenever we want to update the assembly with a new one, we first check-out the item, copy newer assembly to local folder and then check-in it again.
An assembliy (.dll file) in TFS can not be checked-out by multiple users because it’s a binary file and can’t merged or compared. Just like files of type gif. We had a situation recently that a user checked-out one assembly without checking-in it again or undoing his change. As he went to vacation, that assembly remained locked in TFS version control and no one could check-out that assembly again. Me as TFS administrator was forced to unlock it. So googled for the solution and found Martin Woodward’s work-around:
tf lock $/MyProject/MyPath/MyFile.cs /lock:none /workspacename:WorkSpaceName /server:my_server
Unfortunately this was not working for me because I got error:
Tf10152: the item xxx must remain locked because its file type prevents multiple check-outs.
I was very hopeless but another link showed me how to use “undo” to solve my problem. This time it worked nicely:
tf undo /workspace; /server: item
For those unfamiliar with “tf”, it is powerful command-line tool for TFS that can be run from a “Visual Studio Command Prompt” window.
If you are going to start using TFS 2010 please be aware that each TPC (Team Project Collection) needs a separate Build Controller.
For those who are intended to use TFS 2010 as their ALM engine, TFS 2010 can contain several TPCs. Each TPC can contain several Team Projects. Each Team Project is a regular space in TFS that contains Work Item Management, Source Control and Build automation. Build automation in each Team Project contains several Build Definitions that build project with several conditions. Each Build Definition is assigned to a Build Controller. A Build Controller is a build server that builds project using conditions defined in Build Definitions.
In other hands while defining a new Build Definition you must specify its Build Controller. Unfortunately with TFS 2010 you can not use Build Controller defined for say TPC number one for say TPC number two. Each TPC must have its own Build Controller.
Considering that a Build Controller is really a server, assigning a server to each TPC defined in TFS is not very applicable in most companies and teams. There is an article in MSDN blogs that shows a way to use a single Build Controller in several TPCs. As the article itself emphasis, this hack is not recommended for operational installations. Some people like us have been forced to use a single TPC for all Team projects. This work-around has many disadvantages like interfere of Team Projects, security issues, etc, but at least have solved the problem of need to several servers as Build Controllers.
My question in StackOverflow
Related content in TFS forum
Related content in GeeksWithBlogs
Jim Lamb’s hack for the problem