How to rename all symbols using Roslyn? - refactoring

I'm building a Standalone app which will load a folder with c# code, and allow the user to write Regex to select and rename namespace/types/fields/properties/methods/argument/variable/events'name, but i'm stuck at renaming source code.
I have analyzed the SyntaxTree and collected all items, and also searched/matched/renamed with regex.
I have done a plenty of codes trying to get roslyn rename "items", but i only the first "item" is renamed while all the next ones are discarded.
I am aware of Immutability of the Syntax API, and after calling Renamer I save the solution, and also re-search the document in the new solution in the next loop.
//renaming code
var newSolution = await Renamer.RenameSymbolAsync(solution, isymbol, newName, solution.Workspace.Options).ConfigureAwait(false);
this.solution = newSolution;
//re-search code
if (solution.Projects.First ().ContainsDocument(doc.Document.Id)) {
var document = project.GetDocument(doc.Document.Id);
...
}
At the end i call SyntaxTree.GetRoot().ToString (); to get the final edited code, which as mentioned above has only the first edit.
Could anyone explain me the correct way to do this or provide me a sample how this could be implemented so i can try on my own?

Related

Bundleconfig (seemingly) not creating requested .js files

We have a large solution with a number of files being created by bundleconfig.cs. But for some reason the last two projects added to the solution don't seem to be getting the files creating. The pages that use them fail cause they aren't there, or not being found.
Example of project successfully getting the files created:
const string ANGULAR_APP_ROOT_EDI = "~/app/ediViewer/";
const string VIRTUAL_BUNDLE_PATH_EDI = ANGULAR_APP_ROOT_EDI + "main.js";
bundles.Add(
new ScriptBundle(VIRTUAL_BUNDLE_PATH_EDI)
.Include(ANGULAR_APP_ROOT_EDI + "ediViewerApp.js")
.IncludeDirectory(ANGULAR_APP_ROOT_EDI, "*.js", searchSubdirectories: true)
);
Example of one that's not:
const string ANGULAR_APP_ROOT_EDI_SC = "~/app/SupplyChain/";
const string VIRTUAL_BUNDLE_PATH_EDI_SC = ANGULAR_APP_ROOT_EDI_SC + "main.js";
bundles.Add(
new ScriptBundle(VIRTUAL_BUNDLE_PATH_EDI_SC)
.Include(ANGULAR_APP_ROOT_EDI_SC + "SupplyChainApp.js")
.IncludeDirectory(ANGULAR_APP_ROOT_EDI_SC, "*.js", searchSubdirectories: true)
);
very similar, both Angular(js) projects with similar directory structures. but the second one gets no files. I have other projects with a similar structure that are working.
I was hoping there was a way to put breakpoints in the bundleconfig file to see if if it was hitting the code, but apparently you can't, or I didn't successfully set one up.
There are a number of bundles appearing after the new one (the standard Angular libraries) that are getting created, so it doesn't appear to be stopping in the middle or anything.
The workaround was I simply added the scripts needed manually to the aspx page, but I shouldn't have to. It's happened for two new projects so far, so I'm prepared to bet it may happen for a third, so if I can find a fix it'd be useful.
Any ideas what might be happening, or how I can troubleshoot it?

spring-integration-aws dynamic file download

I've a requirement to download a file from S3 based on a message content. In other words, the file to download is previously unknown, I've to search and find it at runtime. S3StreamingMessageSource doesn't seem to be a good fit because:
It relies on polling where as I need to wait for the message.
I can't find any way to create a S3StreamingMessageSource dynamically in the middle of a flow. gateway(IntegrationFlow) looks interesting but what I need is a gateway(Function<Message<?>, IntegrationFlow>) that doesn't exist.
Another candidate is S3MessageHandler but it has no support for listing files which I need for finding the desired file.
I can implement my own message handler using AWS API directly, just wondering if I'm missing something, because this doesn't seem like an unusual requirement. After all, not every app just sits there and keeps polling S3 for new files.
There is S3RemoteFileTemplate with the list() function which you can use in the handle(). Then split() result and call S3MessageHandler for each remote file to download.
Although the last one has functionality to download the whole remote dir.
For anyone coming across this question, this is what I did. The trick is to:
Set filters later, not at construction time. Note that there is no addFilters or getFilters method, so filters can only be set once, and can't be added later. #artem-bilan, this is inconvenient.
Call S3StreamingMessageSource.receive manually.
.handle(String.class, (fileName, h) -> {
if (messageSource instanceof S3StreamingMessageSource) {
S3StreamingMessageSource s3StreamingMessageSource = (S3StreamingMessageSource) messageSource;
ChainFileListFilter<S3ObjectSummary> chainFileListFilter = new ChainFileListFilter<>();
chainFileListFilter.addFilters(
new S3SimplePatternFileListFilter("**/*/*.json.gz"),
new S3PersistentAcceptOnceFileListFilter(metadataStore, ""),
new S3FileListFilter(fileName)
);
s3StreamingMessageSource.setFilter(chainFileListFilter);
return s3StreamingMessageSource.receive();
}
log.warn("Expected: {} but got: {}.",
S3StreamingMessageSource.class.getName(), messageSource.getClass().getName());
return messageSource.receive();
}, spec -> spec
.requiresReply(false) // in case all messages got filtered out
)

Xpath Part NULL, with xpaths set via content control toolkit

I've been able to set, via code, the xpaths for the placeholders found in the document.
for (Object o : finderSdtRun.results) {
if (o instanceof SdtRun){
SdtPr sdtPr=((SdtRun) o).getSdtPr();
Tag t = sdtPr.getTag();
CTDataBinding ctDataBinding = Context.getWmlObjectFactory().createCTDataBinding();
//JAXBElement jaxbDB = Context.getWmlObjectFactory().createSdtPrDataBinding(ctDataBinding);
sdtPr.setDataBinding(ctDataBinding);
ctDataBinding.setXpath("tuttappostaferragost");
ctDataBinding.setStoreItemID("something");
ObjectFactory factory = new org.opendope.xpaths.ObjectFactory();
DataBinding db = factory.createXpathsXpathDataBinding();
db.setXpath("tuttappostaferragost");
db.setStoreItemID("something");
Xpaths.Xpath xp = factory.createXpathsXpath();
xp.setDataBinding(db);
xp.setId("something");
try {
wordMLPackage.getMainDocumentPart().getXPathsPart().getContents().getXpath().add(xp);
} catch (Docx4JException e) {
e.printStackTrace();
}
;
The problem is that, once set, they are not recognized by word, so I thought to add the created Xpaths to a new XpathPart, and then add it to the main Document part.
But I failed because the method:
wordMLPackage.getMainDocumentPart().getXPathsPart()
returns null. This sounded reasonable, since only content control was set, without any Xpath.
Then I set the Xpaths via content control toolkit and the same line of code like above, returned me null, which added a lot of confusion in my yet confused ideas.
Is there any way to tell the document that new Xpath have been added to the document?
I mean, if there is a way to add Xpath via code (the w:databinding w:storedItemId tags), why it is not possible to make it work?
In general I want to add Xpath and all information necessary, via code, avoiding the use of any toolkit.
Thank you :D
First, you have to decide whether you want plain old Word databinding, or the additional OpenDoPE capabilities (which use the content control tag to support repeats, conditionals etc).
You only need an XPaths part if you are using the OpenDoPE extensions.
I'll assume for now that you are just looking to do basic Word content control databinding.
To set that up programmatically, you need to add a custom xml part, and a rel from it to its itemProps.xml part, which contains something like:
<ds:datastoreItem ds:itemID="{5448916C-134B-45E6-B8FE-88CC1FFC17C3}" xmlns:ds="http://schemas.openxmlformats.org/officeDocument/2006/customXml">
<ds:schemaRefs/>
</ds:datastoreItem>
(to add a part B to part A, use partA.addTargetPart)
You can see it is this part with gives the custom xml part its itemID; this corresponds with the value you set in:
DataBinding db = factory.createXpathsXpathDataBinding();
db.setStoreItemID("something");
Then, set the XPath via the method you were using.

how to generate MSTEST results in Static folders

Is there a way to control the name of the MSTEST video recoding file names or the folder names with the test name. It seems to generate different guid everytime and thus very difficult to map the test with its corresponding video recording files.
The only solution I can see is to read the TRX file and map the guid to Test Name.
Any suggestions ??
If you're not opposed to doing it by hand, it's pretty easy. I encountered the same problem, and needed them to be somewhere predictable so I could email links to the videos. In the end my solution just ended up being to code in the functionality by hand. It's a bit involved, but not too difficult.
First, you'll need to have Expression Encoder 4 installed.
Then you'll need to add these references to your project:
Microsoft.Expression.Encoder
Microsoft.Expression.Encoder.Api2
Microsoft.Expression.Encoder.Types
Microsoft.Expression.Encoder.Utilities
Next, you need to add the following inclusion statements:
using Microsoft.Expression.Encoder.Profiles;
using Microsoft.Expression.Encoder.ScreenCapture;
Then you can use [TestInitialize] and [TestCleanup] to define the correct behavior. These methods will run at the beginning and end of each test respectively. This can be done something like this:
[TestInitialize]
public void startVideoCapture()
{
screenCapJob.CaptureRectangle = RectangleSelectionUtilities.GetScreenRect(0);
screenCapJob.CaptureMouseCursor = true;
screenCapJob.ShowFlashingBoundary = false;
screenCapJob.OutputScreenCaptureFileName = "path you want to save to";
screenCapJob.Start();
}
[TestCleanup]
public void stopVideoCapture()
{
screenCapJob.Stop();
}
Obviously this code needs some error and edge case handling, but it should get you started.
You should also know that the free version of Expression Encoder 4 limits you to 10 minutes per video file, so you may want to make a timer that will start a new video for you when it hits 10 minutes.

Copy object values in Visual Studio debug mode

In Visual Studio debug mode it's possible to hover over variables to show their value and then right-click to "Copy", "Copy Expression" or "Copy Value".
In case the variable is an object and not just a basic type, there's a + sign to expand and explore the object. It there a way to copy all that into the clipboard?
In the immediate window, type
?name_of_variable
This will print out everything, and you can manually copy that anywhere you want, or use the immediate window's logging features to automatically write it to a file.
UPDATE: I assume you were asking how to copy/paste the nested structure of the values so that you could either search it textually, or so that you can save it on the side and then later compare the object's state to it. If I'm right, you might want to check out the commercial extension to Visual Studio that I created, called OzCode, which lets you do these thing much more easily through the "Search" and "Compare" features.
UPDATE 2 To answer #ppumkin's question, our new EAP has a new Export feature allows users to Export the variable values to Json, XML, Excel, or C# code.
Full disclosure: I'm the co-creator of the tool I described here.
You can run below code in immediate window and it will export to an xml file the serialized XML representation of an object:
(new System.Xml.Serialization.XmlSerializer(obj.GetType())).Serialize(new System.IO.StreamWriter(#"c:\temp\text.xml"), obj)
Source: Visual Studio how to serialize object from debugger
Most popular answer from https://stackoverflow.com/a/23362097/2680660:
With any luck you have Json.Net in you appdomain already. In which
case pop this into your Immediate window:
Newtonsoft.Json.JsonConvert.SerializeObject(someVariable)
Edit: With .NET Core 3.0, the following works too:
System.Text.Json.JsonSerializer.Serialize(someVariable)
There is a extension called Object Exporter that does this conveniently.
http://www.omarelabd.net/exporting-objects-from-the-visual-studio-debugger/
Extension: https://visualstudiogallery.msdn.microsoft.com/c6a21c68-f815-4895-999f-cd0885d8774f
You can add a watch for that object, and in the watch window, expand and select everything you want to copy and then copy it.
By using attributes to decorate your classes and methods you can have a specific value from your object display during debugging with the DebuggerDisplay attribute e.g.
[DebuggerDisplay("Person - {Name} is {Age} years old")]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
I always use:
string myJsonString = JsonConvert.SerializeObject(<some object>);
Then I copy the string value which unfortunately also copies the back slashes.
To remove the backlashes go here:
https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_replace
Then within the <p id="demo">Visit Microsoft!</p> element replace the text with the text you copied.
then replace the var res = str.replace("Microsoft", "W3Schools"); line with
var res = str.replace(/\\/g, '')
Run these new changes but don't forget to click the "try it" button on the right.
Now you should have all the text of the object in json format that you can drop in a json formatter like http://jsonformatter.org or to create a POCO you can now use http://json2csharp.com/
ObjectDumper.NET
This is an awesome way!
You probably need this data for a unit test, so create a Sandbox.cs temporary test or you can create a Console App.
Make sure to get NuGet package, ObjectDumper.NET, not ObjectDumper.
Run this test (or console app)
View test output or text file to get the C# initializer code!
Code:
[TestClass]
public class Sandbox
{
[TestMethod]
public void GetInitializerCode()
{
var db = TestServices.GetDbContext();
var list = db.MyObjects.ToList();
var literal = ObjectDumper.Dump(list, new DumpOptions
{
DumpStyle = DumpStyle.CSharp,
IndentSize = 4
});
Console.WriteLine(literal); // Some test runners will truncate this, so use the file in that case.
File.WriteAllText(#"C:\temp\dump.txt", literal);
}
}
I used to use Object Exporter, but it is 5 years old and no longer supported in Visual Studio. It seems like Visual Studio Extensions come and go, but let's hope this NuGet package is here to stay! (Also it is actively maintained as of this writing.)
Google led me to this 8-year-old question and I ended up using ObjectDumper to achieve something very similar to copy-pasting debugger data. It was a breeze.
I know the question asked specifically about information from the debugger, but ObjectDumper gives information that is basically the same. I'm assuming those who google this question are like me and just need the data for debugging purposes and don't care whether it technically comes from the debugger or not.
I know I'm a bit late to the party, but I wrote a JSON implementation for serializing an object, if you prefer to have JSON output. Uses Newtonsoft.Json reference.
private static void WriteDebugJSON (dynamic obj, string filePath)
{
using (StreamWriter d = new StreamWriter(filePath))
{
d.Write(JsonConvert.SerializeObject(obj));
}
}
I've just right clicked on the variable and selected AddWatch, that's bring up watch window that consists of all the values. I selected all and paste it in a text a text editor, that's all.
Object Dumper is a free and open source extension for Visual Studio and Visual Studio Code.
"Dump as" commands are available via context menu in the Code and Immediate windows.
It's exporting objects to:
C# object initialization code,
JSON,
Visual Basic object initialization code,
XML,
YAML.
I believe that combined with the Diff tool it can be helpful.
I'm the author of this tool.
if you have a list and you want to find a specific variable:
In the immediate window, type
myList.Any(s => s.ID == 5062);
if this returns true
var myDebugVar = myList.FirstOrDefault(s => s.ID == 5062);
?myDebugVar
useful tips here, I'll add my preference for when i next end up here asking this question again in the future.
if you don't mind adding an extension that doesn't require output files or such there's the Hex Visualizer extension for visual studio, by mladen mihajlovic, he's done versions since 2015.
provides a nice display of the array via the usual magnifine glass view object from the local variables window.
https://marketplace.visualstudio.com/items?itemName=Mika76.HexVisualizer2019 is the 2019 version.
If you're in debug mode, you can copy any variable by writing copy() in the debug terminal.
This works with nested objects and also removes truncation and copies the complete value.
Tip: you can right click a variable, and click Copy as Expression and then paste that in the copy-function.
System.IO.File.WriteAllText("b.json", page.DebugInfo().ToJson())
Works great to avoid to deal with string debug format " for quote.
As #OmerRaviv says, you can go to Debug → Windows → Immediate where you can type:
myVariable
(as #bombek pointed out in the comments you don't need the question mark) although as some have found this limits to 100 lines.
I found a better way was to right click the variable → Add Watch, then press the + for anything I wanted to expand, then used #GeneWhitaker's solution, which is Ctrl+A, then copy Ctrl+C and paste into a text editor Ctrl+V.

Resources