Is it possible to run auto-format code for all or for specific file in solution, like (Ctrl+K, Ctrl+D) formatting in Visual Studio but from it`s command line?
Or use Resharper's cleanup also from command line for solution files?
Create your own tool. You can use EnvDTE, EnvDTE80 to create Visual Studio project and load the files you want to format on the fly. Once you are done delete the Visual Studio project. You can specify to not to show Visual Studio window while formatting. If you are interested let me know I can give you some code to make this work.
UPDATE:
I am copying the code I have. I used it to format *.js files. I removed some code which you don't need. Feel free to ask if it doesn't work.
//You need to make a reference to two dlls:
envdte
envdte80
void FormatFiles(List<FileInfo> files)
{
//If it throws exeption you may want to retry couple more times
EnvDTE.Solution soln = System.Activator.CreateInstance(Type.GetTypeFromProgID("VisualStudio.Solution.11.0")) as EnvDTE.Solution;
//try this if you have Visual Studio 2010
//EnvDTE.Solution soln = System.Activator.CreateInstance(Type.GetTypeFromProgID("VisualStudio.Solution.10.0")) as EnvDTE.Solution;
soln.DTE.MainWindow.Visible = false;
EnvDTE80.Solution2 soln2 = soln as EnvDTE80.Solution2;
//Creating Visual Studio project
string csTemplatePath = soln2.GetProjectTemplate("ConsoleApplication.zip", "CSharp");
soln.AddFromTemplate(csTemplatePath, tempPath, "FormattingFiles", false);
//If it throws exeption you may want to retry couple more times
Project project = soln.Projects.Item(1);
foreach (FileInfo file in files)
{
ProjectItem addedItem;
bool existingFile = false;
int _try = 0;
while (true)
{
try
{
string fileName = file.Name;
_try++;
if (existingFile)
{
fileName = file.Name.Substring(0, (file.Name.Length - file.Extension.Length) - 1);
fileName = fileName + "_" + _try + file.Extension;
}
addedItem = project.ProjectItems.AddFromTemplate(file.FullName, fileName);
existingFile = false;
break;
}
catch(Exception ex)
{
if (ex.Message.Contains(file.Name) && ex.Message.Contains("already a linked file"))
{
existingFile = true;
}
}
}
while (true)
{
//sometimes formatting file might throw an exception. Thats why I am using loop.
//usually first time will work
try
{
addedItem.Open(Constants.vsViewKindCode);
addedItem.Document.Activate();
addedItem.Document.DTE.ExecuteCommand("Edit.FormatDocument");
addedItem.SaveAs(file.FullName);
break;
}
catch
{
//repeat
}
}
}
try
{
soln.Close();
soln2.Close();
soln = null;
soln2 = null;
}
catch
{
//for some reason throws exception. Not all the times.
//if this doesn't closes the solution CleanUp() will take care of this thing
}
finally
{
CleanUp();
}
}
void CleanUp()
{
List<System.Diagnostics.Process> visualStudioProcesses = System.Diagnostics.Process.GetProcesses().Where(p => p.ProcessName.Contains("devenv")).ToList();
foreach (System.Diagnostics.Process process in visualStudioProcesses)
{
if (process.MainWindowTitle == "")
{
process.Kill();
break;
}
}
tempPath = System.IO.Path.GetTempPath();
tempPath = tempPath + "\\FormattingFiles";
new DirectoryInfo(tempPath).Delete(true);
}
I hope this helps.
To format net core c# source, use https://github.com/dotnet/format
Install the tool as per the project readme.
I had a need to format some code files I was generating from Razor templates. I created a shell .CSProj file in the root of my output folder, using dotnet new console which gives you this basic file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RootNamespace>dotnet_format</RootNamespace>
</PropertyGroup>
</Project>
Then run dotnet format from a VS command prompt in that folder. It will recurse into sub-directories and format everything it finds. To format specific files you can provide a list of filenames with the --files switch.
As a followup to Dilshod's post, if you're just looking to format a single file, here's a way of doing it that won't need a temporary path:
static void FormatFile(string file)
{
EnvDTE.Solution soln = System.Activator.CreateInstance(
Type.GetTypeFromProgID("VisualStudio.Solution.10.0")) as EnvDTE.Solution;
soln.DTE.ItemOperations.OpenFile(file);
TextSelection selection = soln.DTE.ActiveDocument.Selection as TextSelection;
selection.SelectAll();
selection.SmartFormat();
soln.DTE.ActiveDocument.Save();
}
Note that "file" will need to have the full path on disk in all likelihood. Relative paths don't seem to work (though I didn't try all that hard).
Use CodeFormatter from the .NET Team
Install MSBuild Tools 2015.
Download CodeFormatter 1.0.0-alpha6.
Add CodeFormatter.csproj to the root directory of your projects:
CodeFormatter.csproj
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
<Target Name="Compile">
<Csc Sources="#(Compile)"/>
</Target>
</Project>
Then run this from the Command Line.
> codeformatter.exe CodeFormatter.csproj /nocopyright
The result: all your projects' C# files now adhere to the majority of the .NET Foundation coding guidelines.
Remarks
Installing MSBuild Tools 2015 means that we do not need Visual Studio.
Adding CodeFormatter.csproj to the root directory recursively includes all C# files, which means the above works with project.json and *.xproj based setups.
See also
http://bigfontblog.azurewebsites.net/autoformat/
Not possible with Visual Studio, but there are command line utilities for this: http://astyle.sourceforge.net/astyle.html
Related
I have a Windows Forms application that uses Selenium. I have multiple production clients that need to run this application and I’ve noticed that in every new client (and also when I need to update the webdriver) I need to copy and paste the .exe to the [PATH] location (%USERPROFILE%\AppData\Local\Microsoft\WindowsApps) and I want to automate that with the setup file that gets generated by Visual Studio every time I publish the application.
I’ve found that you can install an extension called “Microsoft Visual Studio Installer Project”, include the .exe file on it and either make a new Form that’ll check if the webdriver is in place and if it’s not to copy it, or I can change the [PATH] of my IWebDriver object in order to reflect the new path of this file. As a bonus you can also add the the desktop icon.
But first I want to know if there’s a way to publish this webdriver.exe file to it’s proper address through the “Publish wizard” parameters before I start looking for workarounds.
This worked for my use case, for context, I'm using a windows forms project targeting .NET (framework) 4.7.1. these are snippets from my events "load" and "show" formated as a different function. I only included the logic behind the file check, download and unzip with overwite. Since the System.IO.Compression.ZipFile class for this version of .NET doesn't natively support overwrite files, I used Ionic's DotNetZip package downloaded from NuGet.
using Ionic.Zip;
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
private void DriverCheck(){
string edge, edgeVersion, edgeDriverPath, edgeDriver, edgeDriverVersion;
edge = #"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe";
edgeVersion = FileVersionInfo.GetVersionInfo(edge).FileVersion;
edgeDriverPath = Environment.GetEnvironmentVariable("LocalAppData") + "\\Microsoft\\WindowsApps\\";
edgeDriver = edgeDriverPath + "msedgedriver.exe";
try
{
edgeDriverVersion = FileVersionInfo.GetVersionInfo(edgeDriver).FileVersion;
}
catch
{
edgeDriverVersion = null;
}
if (!File.Exists(edgeDriver) || edgeVersion != edgeDriverVersion)
{
try
{
using (var client = new WebClient())
{
string winver;
if (Environment.Is64BitProcess)
{
winver = "64";
}
else
{
winver = "32";
}
string zipPath = edgeDriverPath + "edgedriver_win64.zip";
client.DownloadFile("https://msedgedriver.azureedge.net/" + edgeVersion + "/edgedriver_win" + winver + ".zip", zipPath);
using (ZipFile zip = ZipFile.Read(zipPath))
{
foreach (ZipEntry temp in zip)
{
temp.Extract(edgeDriverPath, ExtractExistingFileAction.OverwriteSilently);
}
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error downloading webdriver:\n" + ex.Message);
Application.Exit();
}
}
}
I'm having trouble getting my log4net.config file to load when using Visual Studio in debug mode for an Excel VSTO Plugin. The config file is in the top level directory of my project. I have the property "Copy to Output Directory" set to "Copy Always". This ensures the file is copied to bin/Debug/log4net.config. I can verify this is the case when I build.
However, the file won't load when I run in Debug mode. I gave up on trying to get the file to load automatically and decided to do it by code, as per the OP's code at the bottom of this question.
However, I realised that I needed to use an absolute path to the config file, as relative paths weren't picking it up. On further investigation, I realised that the executing DLL wasn't actually the DLL in the debug/bin folder. It was in the following location:
C:\Users\cbhandal\AppData\Local\assembly\dl3\MO52QQWP.9ZL\K36XZHGN.1PB\230751e6\d09b7fb2_19f6d401
Also the current working directory, as found by System.IO.Directory.GetCurrentDirectory(); was set to "C:\\Users\\cbhandal\\Documents".
Hard-coding the path as an absolute path works as in the following code:
var log4netConfig = "C:\\" + path + "\\Log4net.config";
var log4netInfo = new FileInfo(log4netConfig);
log4net.Config.XmlConfigurator.ConfigureAndWatch(log4netInfo);
But that's not a solution I can deploy. I'm stuck here. Wondering if there's a way to either force Visual studio to copy the .config file to that appdata/temp location, or if there's a way to programatically reference the folder where the original DLL lay- the one that was built. Or if anyone had any other solution?
For me the easiest solution was to use this:
https://stackoverflow.com/a/6963420/4754981
But there are several other solutions on that link for different approaches, each with their caveats.
So mine looks like this:
using System.Reflection;
using System.IO;
using System;
public static class Extensions {
private static string GetDirectory(this Assembly a) {
string codeBase = a.CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
private static void AlterLogPath(this log4net.Repository.ILoggerRepository repo, string newPath, string directory="") {
log4net.Repository.Hierarchy.Hierarchy h = (log4net.Repository.Hierarchy.Hierarchy) repo;
foreach (log4net.Appender.IAppender a in h.Root.Appenders) {
if (a is log4net.Appender.FileAppender) {
var fa = (log4net.Appender.FileAppender)a;
var fileName = Path.GetFileName(fa.File);
fa.File = newPath + (String.IsNullOrEmpty(directory)?"":(directory + Path.DirectorySeparatorChar.ToString())); // edit: filename is attached after next line automatically.
fa.ActivateOptions();
break;
}
}
}
}
and in the bootup (via [assembly: System.Web.PreApplicationStartMethod] or otherwise for asp), or main app..
static void Main() {
var PATH = Assembly.GetExecutingAssembly().GetDirectory() + Path.DirectorySeparatorChar.ToString();
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(PATH + "log4net.config"));
log4net.LogManager.GetRepository().AlterLogPath(PATH, "Logs");
}
In My C# language sln file contains two projects. first project has the actual code & second project has the unittest cases for the first project. but while am doing the resharper code analysis using Command line tool (inspectcode.exe).
for both project resharper doing the inspection in the unit test project only, not on the Actual code file.
'
package org.sonar.plugins.resharper;
import java.io.File;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.utils.command.Command;
import org.sonar.api.utils.command.CommandException;
import org.sonar.api.utils.command.CommandExecutor;
public class ReSharperExecutor
{
private static final Logger LOG = LoggerFactory.getLogger(ReSharperExecutor.class);
public void execute(String executable, String project, String solutionFile, File rulesetFile, File reportFile, int timeout)
{
Command cmd = Command.create(getExecutable(executable)).addArgument("/output=" + reportFile.getAbsolutePath()).addArgument("/no-swea").addArgument("/project=" + project).addArgument("/profile=" + rulesetFile.getAbsolutePath()).addArgument("/no-buildin-settings").addArgument(solutionFile);
int exitCode = CommandExecutor.create().execute(cmd, TimeUnit.MINUTES.toMillis(timeout));
if (exitCode != 0) {
throw new CommandException(cmd, "ReSharper execution failed with exit code: " + exitCode, null);
}
}
private static String getExecutable(String propertyValue)
{
String execName = "inspectcode.exe";
if (!propertyValue.endsWith(execName)) {
return new File(propertyValue, execName).getAbsolutePath();
}
return propertyValue;
}
}'
Where I need to do the change to do the Resharper analysis for the Actual code.
Executing command: cd:/inspectcode.exe /output=cd:\resharper-report.xml /no-swea /project=* /profile=cd:.sonar\resharper-sonarqube.DotSettings /no-buildin-settings cd:\XXXX.sln
The above issue was caused bcoz the VS build version different in the
1.project built machine(VS2015) &
2.project analysis happening machine(VS2013),
so its not show any error details in log of the machine 2.
After testing the analysis in the built machine i got the root cause of the issue(Few of the dependency library of the project was missed which should be availble under MSBuild folder{Msbuildfolder->Microsoft->visualstudio->version}) & fixed it(by replacing the missing dll's).
Now Analysis running successfully.
I have TeamCity running for a C# project. The Unit tests are written using MSTest and they include an external JSON file. They are loaded in because they're large and I don't want to have to escape them in C#.
I import them like this:
[TestInitialize]
public void Setup()
{
using (StreamReader r = new StreamReader(#".\currency2.json"))
{
_json = r.ReadToEnd();
}
...
They run fine locally. I have 'Copy always set' but when the tests are ran using Teamcity I get an error saying that it can't find them in a temp folder. They are copied over to the build server but they're not in this temp folder.
Could not find file 'E:\TeamCity\buildAgent\temp\buildTmp\SYSTEM_SERVER 2016-07-18 15_28_19\Out\currency2.json'
I have **\bin\release\*test*.dll setup as my Test File Names in the test build step.
Any help appreciated.
I had a similar problem.
I changed the properties of the test file to this
Build Action = Content
Copy to Output Directory = Copy always
Teamcity will copy the file to the build folder, but it does not seem to maintain the same structure you'd expect.
So I created a file lookup loop. That will step down the expected folder until it finds the text file in question.
var pathLookups = new string[]
{
"2ndFolder\\3rdFolder\\test.json", // folder that normally workes
"3rdFolder\\test.json",
"test.json"
};
foreach (var pathLookup in pathLookups)
{
try
{
jsonFileCollection = JsonFileLoader<TestJsonType>.LoadJson(pathLooksup);
if (jsonFileCollection!= null)
{
break;
}
}
catch (Exception)
{
Console.WriteLine("Attempted to load test json from path:" + pathLooksup);
}
}
It's not the cleanest solution, but it will get the job done. You could refactor this to look a little nicer.
You might pass the full pass by argument to your program (and value defined in TeamCity).
Something like this (this is a pseudo-code example only) :
string[] programArgs;
static void Main(string[] args)
{
programArgs = args
}
[TestInitialize]
public void Setup()
{
using (StreamReader r = new StreamReader(programArgs[1]))
{
_json = r.ReadToEnd();
}
...
}
I have not found yet a file-rename-function in .NET for C#, so I'm a bit confused how I would rename a file. I use the command prompt with Process.Start, but this isn't really professional and a black DOS window is popping up each time. Yes, I know there is something in the Visual Basic namespace, but this is not my intention to add the "visual-basic.dll" to my project.
I found some examples which "move" the file to rename it. It is a quite painful method and a shoddy workaround for things. Such footwork I can program myself.
Every language has renaming commands, so I am stunned that C# hasn't or I haven't found out yet. What is the right command?
For large files and to rename on CD, this code works, but your project will be partly converted into Visual Basic (as I understand it, maybe it is not so):
//Add the Microsoft.VisualBasic.MyServices reference and namespace in a project;
//For directories:
private static bool RenameDirectory(string DirPath, string NewName)
{
try
{
FileSystemProxy FileSystem = new Microsoft.VisualBasic.Devices.Computer().FileSystem;
FileSystem.RenameDirectory(DirPath, NewName);
FileSystem = null;
return true;
}
catch {
return false;
} //Just shut up the error generator of Visual Studio
}
//For files:
private static bool RenameFile(string FilePath, string NewName)
{
try
{
FileSystemProxy FileSystem = new Microsoft.VisualBasic.Devices.Computer().FileSystem;
FileSystem.RenameFile(FilePath, NewName);
FileSystem = null;
return true;
}
catch {
return false;
} //Just shut up the error generator of Visual Studio
}
A rename is just a move and vice versa, see the MSDN : File.Move
In the OS the operations are the same for all intents an purposes. That's why in explorer a move on the same partition is near instantaneous - just adjusts the file name and logical location. To Rename a file in the same directory you Move it to a new File Name in the same directory.
using System;
using System.IO;
class Test
{
public static void Main()
{
string path = #"c:\temp\MyTest.txt";
string path2 = #"c:\temp2\MyTest.txt";
try
{
if (!File.Exists(path))
{
// This statement ensures that the file is created,
// but the handle is not kept.
using (FileStream fs = File.Create(path)) {}
}
// Ensure that the target does not exist.
if (File.Exists(path2))
File.Delete(path2);
// Move the file.
File.Move(path, path2);
Console.WriteLine("{0} was moved/renamed to {1}.", path, path2);
// See if the original exists now.
if (File.Exists(path))
{
Console.WriteLine("The original file still exists, which is unexpected.");
}
else
{
Console.WriteLine("The original file no longer exists, which is expected.");
}
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
}
}