Seperation of db connection in seperate class file doesn't work - c#

Rookie here needing help. I'm trying to build a prototype with the neo4j .NET driver using Bolt. My aim with the prototype is building multiple methods for creation and searches in the db, but only one method to connect to the db - here I'm continuously having problems. I've Googled all weekend for examples, tutorials and traversed through the documentation and now I need your help.
Programs.cs
using System;
using DTUneo4jConsoleApp.Db;
namespace DTUneo4jConsoleApp
{
public class Program
{
public static void Main(string[] args)
{
MyProperties something = new MyProperties();
neo4jdb session = new neo4jdb();
session.Run($"CREATE (a:Person {{name:'{something.Name}', title:'{something.Title}'}})");
var result = session.Run($"MATCH (a:Person) WHERE a.name = '{something.Name}' RETURN a.name AS name, a.title AS title");
foreach (var record in result)
{
Console.WriteLine($"{record["title"].As<string>()} {record["name"].As<string>()}");
}
Console.ReadKey();
}
}
public class MyProperties
{
public string Name { get; set; }
public string Title { get; set; }
}
}
db.cs
using Neo4j.Driver.V1;
namespace DTUneo4jConsoleApp.Db
{
public class neo4jdb
{
public static void Connection()
{
using (var driver = GraphDatabase.Driver("bolt://localhost", AuthTokens.Basic("user", "pass")))
using (var session = driver.Session())
{
}
}
}
}
When I instantiate the neo4jdb session = new neo4jdb(); I don't get i.e. the Run() method from the driver.
I hope someone can guide me in the right direction.

I am doing it like this:
public static List<IStatementResult> ExecuteCypher(List<Statement> statements)
{
List<IStatementResult> results = new List<IStatementResult>();
using (var driver = GraphDatabase.Driver("bolt://localhost", AuthTokens.Basic("user", "pass")))
{
using (var session = driver.Session())
{
using (var tx = session.BeginTransaction())
{
foreach (var statement in statements)
{
results.Add(tx.Run(statement));
}
tx.Success();
}
}
}
return results;
}
usage:
MyProperties something = new MyProperties();
var createCypher = new Statement($"CREATE (a:Person {{name:'{something.Name}', title:'{something.Title}'}})");
var matchCypher = new Statement($"MATCH (a:Person) WHERE a.name = '{something.Name}' RETURN a.name AS name, a.title AS title");
var statements = new List<Statement>();
statements.Add(createCypher);
statements.Add(matchCypher);
var results = ExecuteCypher(statements);
//you can now query result for each statement or
//your query your desired result
foreach (var record in results.Last())
{
Console.WriteLine($"{record["title"].As<string>()} {record["name"].As<string>()}");
}
In this way I can also create multiple records in a single transaction and get the result of all those as well.

Related

How to use InsertMany properly Mongodb C#

Hi I wont to pass some synthetic data to my database with the method InsertMany i have write the flowing code:
My Main:
static void Main(string[] args)
{
MongoCRUD db = new MongoCRUD("testClass");
List<GlobalUrbanPoint> syntheticData = CreateSunfeticData(20);
db.InsertMultipleRecords<GlobalUrbanPoint>("geo3", syntheticData);
}
My model class:
public class GlobalUrbanPoint
{
[BsonId]
public ObjectId Id{ get; set; }
public string NAME { get; set; }
}
The function for the synthetic data:
public static List<GlobalUrbanPoint> CreateSunfeticData(int NumberOfDocumet)
{
List<GlobalUrbanPoint> SyntheticList = new List<GlobalUrbanPoint>();
var SyntheticObject = new GlobalUrbanPoint();
for (var i = 1; i < NumberOfDocumet; i++)
{
SyntheticObject.NAME = (i+1).ToString();
SyntheticList.Add(SyntheticObject);
}
return SyntheticList;
}
And for my operation i use MongoCRUD
public class MongoCRUD
{
private IMongoDatabase db;
public MongoCRUD(string database)
{
var client = new MongoClient();
db = client.GetDatabase(database);
}
public void InsertRecord<T>(string table, T record)
{
var collection = db.GetCollection<T>(table);
collection.InsertOne(record);
}
public void InsertMultipleRecords<T>(string table, List<T> records)
{
var collection = db.GetCollection<T>(table);
collection.InsertMany(records);
}
}
When i run the code i get an error E11000 duplicate key error collection. I check the definition of InsertMany and it takes for arguments IEnumerable<TDocument> documents. It is an easy way to convert List<T> to IEnumerable<TDocument>?
What i need to change my synthetic function or my InsertMultipleRecords funtion. Any sugestion?
Thank you for your time.
After some digging i found that the object that i create in synthetic function has the same _id. For that i needed to change the creation of the object, inside of for loop. And my problem it was not in InsertMultipleRecords.
public static List<GlobalUrbanPoint> CreateSunfeticData(int NumberOfDocumet)
{
List<GlobalUrbanPoint> SyntheticList = new List<GlobalUrbanPoint>();
for (var i = 1; i < NumberOfDocumet; i++)
{
var SyntheticObject = new GlobalUrbanPoint();
SyntheticObject.NAME = (i+1).ToString();
SyntheticList.Add(SyntheticObject);
}
return SyntheticList;
}

set type dynamically using Createmany

I have different types of documents that are derived from a base type called Topic. I'd like to use:
Client.Bulk(b => b.CreateMany(documents)
to be able to process all the documents with a single call to Bulk, how can I set the type for each document?
Here is a snippet of code:
public IEnumerable<IBulkResponse> CreateBulkTopics(IEnumerable<Topic> topics)
{
var results = new List<IBulkResponse>();
results.Add(IndexDocuments(TopicFactory.ConvertDrugsToDocuments(topics)));
results.Add(IndexDocuments(TopicFactory.ConvertTreatmentSummariesToDocuments(topics)));
return results;
}
public IBulkResponse IndexDocuments(IEnumerable<Common.Elastic.Models.Topic> documents)
{
return ElasticConnector.Client.Bulk(b => b.CreateMany(documents));
}
The problem at this minute is all the documents are being stored as "topic" as opposed to the derived types such as drugs and treatmentsummaries.
How many types inherit from Topic? Are they constant and small? Then something like this can help. Lets say TopicA and TopicB inherit from Topic:
public IEnumerable<IBulkResponse> IndexDocuments(IEnumerable<Common.Elastic.Models.Topic> documents)
{
yield return ElasticConnector.Client.Bulk(b => b.CreateMany(documents.OfType<TopicA>()));
yield return ElasticConnector.Client.Bulk(b => b.CreateMany(documents.OfType<TopicB>()));
}
and then in CreateBulkTopics:
results.AddRange(IndexDocuments(....
Of course this is only effective if the number of subclasses is small and available to this code. Otherwise, you can use reflection to achieve the same result. The sample code is a bit more complex, but tell me if you need it. Also, this will degrade performance in case the number of subclasses is very high, as it will send each type in a separate request to Bulk api. I can think of no better apprach in the client.
EDIT: This is how you do it using reflection:
class MyClass
{
public IBulkResponse IndexDocuments<T>(IEnumerable<Topic> documents)
where T : Topic
{
var derived = documents.OfType<T>();
return ElasticConnector.Client.Bulk(b => b.CreateMany(derived));
}
public IEnumerable<IBulkResponse> IndexDocumentsByType(IEnumerable<Topic> documents)
{
var groups = documents.GroupBy(x => x.GetType());
var method = typeof(MyClass).GetMethod(nameof(IndexDocuments)); //prior to c#6, typeof(MyClass).GetMethod("IndexDocuments")
foreach (var group in groups)
{
var generic = method.MakeGenericMethod(group.Key);
var result = generic.Invoke(this, new object[] { group });
yield return result as IBulkResponse;
}
}
}
class Program
{
static void Main(string[] args)
{
var documents = new Topic[] { new TopicA(), new TopicA(), new TopicB(), new Topic() };
var result = new MyClass().IndexDocumentsByType(documents);
Console.WriteLine(result.Count()); //writes 3
}
}
I've managed to do it using a generic class:
public class IndexOperations<T> where T:Topic
{
public ElasticConnector ElasticConnector { get; set; }
public IndexOperations(ElasticConnector elasticConnector)
{
ElasticConnector = elasticConnector;
}
public IBulkResponse CreateMany(IEnumerable<T> t)
{
return ElasticConnector.Client.Bulk(b => b.CreateMany(t));
}
}
Client code:
var documents = TopicFactory.ConvertToDocuments(topics);
SaveDrugs(documents);
public IBulkResponse SaveDrugs(IEnumerable<Common.Elastic.Models.Topic> documents)
{
var indexOperations = new IndexOperations<Drug>(ElasticConnector);
return indexOperations.CreateMany(documents.OfType<Drug>());
}

SQLite and "Database is Locked"

Using SQLite, System.Data.SQLite and Dapper (in a Console Application; later Windows Service; high throughput); why "database is locked" is there anyway?
I even abstracted all calling to SQLite db in this method:
public static void LocalDbScope(Action<IDbConnection> action)
{
try
{
lock (DbLock)
{
using (var connection = Open(LocalStorageConnectionString))
{
action(connection);
}
}
}
catch (Exception xux)
{
ErrLog.Error(xux);
throw;
}
}
Turning on the memory-mapped option did not help either:
connection.Execute("PRAGMA wal_autocheckpoint=32; PRAGMA journal_size_limit = 2048;");
connection.Execute("PRAGMA mmap_size=" + GB);
And this is connection string:
var builder = new SQLiteConnectionStringBuilder
{
DataSource = storageDbFilePath,
FailIfMissing = false,
PageSize = 32 * KB,
CacheSize = 10 * MB,
ForeignKeys = false,
UseUTF16Encoding = false,
Pooling = true,
JournalMode = SQLiteJournalModeEnum.Wal,
SyncMode = SynchronizationModes.Normal,
DateTimeKind = DateTimeKind.Utc,
DateTimeFormat = SQLiteDateFormats.ISO8601,
DefaultIsolationLevel = IsolationLevel.ReadCommitted,
DefaultTimeout = (int)TimeSpan.FromMinutes(1).TotalMilliseconds
};
LocalStorageConnectionString = builder.ToString();
What am I missing here?
Note: When you google for "database is locked", all the top results (and whole first page) is about this problem in different programming languages and platforms. It seems there is something else about SQLite that I can not filter out of this picture.
As stated in my comment, I have NO idea what-so-ever, is going on without seeing more of your code.
Still, if you are not willing to change Dapper to Sqlite-net, below is a small non-blocking example, using your abstraction, which is not throwing any exceptions. Hope it helps you figure it out.
using System;
using System.Data;
using System.Data.SQLite;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Dapper;
namespace MyConsoleApplication
{
public class Program
{
static void Main(string[] args)
{
var test = new TestSQLite();
test.GoForIt();
}
}
public class Entity
{
public int Id { get; set; }
public string Content { get; set; }
}
public class TestSQLite
{
private const string ConnectionString = "Data Source=sqlitetest.sqlite";
private static readonly object DbLock = new object();
public void GoForIt()
{
CreateTable();
var random = new Random();
for (int i = 0; i < 100; i++)
{
if ( i % 2 != 0)
{
Task.Factory.StartNew(() => Thread.Sleep(random.Next(0, 200))).ContinueWith(other =>
LocalDbScope(action =>
{
var entity = new Entity {Content = "hoax"};
entity.Id = action.Query<int>(
#"insert into entity (content) values (#Content); select last_insert_rowid()",
entity).First();
var ids = action.Query<int>(#"select id from entity").ToList();
Console.WriteLine("Inserted id:{0}, all ids:[{1}]", entity.Id, string.Join(",", ids));
}));
}
else
{
Task.Factory.StartNew(() => Thread.Sleep(random.Next(200, 500))).ContinueWith(other =>
LocalDbScope(action =>
{
action.Execute(#"delete from entity");
Console.WriteLine("Deleted all entities");
}));
}
}
Console.ReadLine();
}
public static void LocalDbScope(Action<IDbConnection> action)
{
lock (DbLock)
{
using (var connection = new SQLiteConnection(ConnectionString))
action(connection);
}
}
private static void CreateTable()
{
using (IDbConnection c = new SQLiteConnection(ConnectionString))
{
c.Execute(#"drop table if exists entity");
c.Execute(#"create table entity (id integer primary key autoincrement, content varchar(100))");
}
}
}
}

Elastic Search to search for words that starts with phrase

I'm trying to create a search function for my website using Elastic Search and NEST. You can see my code below and I get results if I search for complete (and almost comlete) words.
Ie, if I search for "Buttermilk" or "Buttermil" I get a hit on my document containing the word "Buttermilk".
However, what I try to accomplish is if I search for "Butter", I should have a result with all three documents which have words that starts with "Butter". I thought this was solved by using FuzzyLikeThis?
Can anyone see what I'm doing wrong and point me in the right direction?
I created a console-app and the complete code you can see here:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nest;
using Newtonsoft.Json;
namespace ElasticSearchTest
{
class Program
{
static void Main(string[] args)
{
var indexSettings = new IndexSettings();
indexSettings.Analysis.Analyzers["text-en"] = new SnowballAnalyzer { Language = "English" };
ElasticClient.CreateIndex("elastictesting", indexSettings);
var testItem1 = new TestItem {
Id = 1,
Name = "Buttermilk"
};
ElasticClient.Index(testItem1, "elastictesting", "TestItem", testItem1.Id);
var testItem2 = new TestItem {
Id = 2,
Name = "Buttercream"
};
ElasticClient.Index(testItem2, "elastictesting", "TestItem", testItem2.Id);
var testItem3 = new TestItem {
Id = 3,
Name = "Butternut"
};
ElasticClient.Index(testItem3, "elastictesting", "TestItem", testItem3.Id);
Console.WriteLine("Write search phrase:");
var searchPhrase = Console.ReadLine();
var searchResults = Search(searchPhrase);
Console.WriteLine("Number of search results: " + searchResults.Count());
foreach (var item in searchResults) {
Console.WriteLine(item.Name);
}
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
private static List<TestItem> Search(string searchPhrase)
{
var query = BuildQuery(searchPhrase);
var result = ElasticClient
.Search(query)
.Documents
.Select(d => d)
.Distinct()
.ToList();
return result;
}
public static ElasticClient ElasticClient
{
get
{
var localhost = new Uri("http://localhost:9200");
var setting = new ConnectionSettings(localhost);
setting.SetDefaultIndex("elastictesting");
return new ElasticClient(setting);
}
}
private static SearchDescriptor<TestItem> BuildQuery(string searchPhrase)
{
var querifiedKeywords = string.Join(" AND ", searchPhrase.Split(' '));
var filters = new BaseFilter[1];
filters[0] = Filter<TestItem>.Bool(b => b.Should(m => m.Query(q =>
q.FuzzyLikeThis(flt =>
flt.OnFields(new[] {
"name"
}).LikeText(querifiedKeywords)
.PrefixLength(2)
.MaxQueryTerms(1)
.Boost(2))
)));
var searchDescriptor = new SearchDescriptor<TestItem>()
.Filter(f => f.Bool(b => b.Must(filters)))
.Index("elastictesting")
.Type("TestItem")
.Size(500);
var jsons = JsonConvert.SerializeObject(searchDescriptor, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
return searchDescriptor;
}
}
class TestItem {
public int Id { get; set; }
[ElasticProperty(Analyzer = "text-en", Index = FieldIndexOption.analyzed)]
public string Name { get; set; }
}
}
Edited 2014-04-01 11:18
Well, I ended up using MultiMatch and QueryString, so this it how my code looks now. Hope it mey help anyone in the furure. Also, I added a Description property to my TestItem to illustrate multimatch.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nest;
using Newtonsoft.Json;
namespace ElasticSearchTest
{
class Program
{
static void Main(string[] args)
{
var indexSettings = new IndexSettings();
ElasticClient.CreateIndex("elastictesting", indexSettings);
var testItem1 = new TestItem {
Id = 1,
Name = "Buttermilk",
Description = "butter with milk"
};
ElasticClient.Index(testItem1, "elastictesting", "TestItem", testItem1.Id);
var testItem2 = new TestItem {
Id = 2,
Name = "Buttercream",
Description = "Butter with cream"
};
ElasticClient.Index(testItem2, "elastictesting", "TestItem", testItem2.Id);
var testItem3 = new TestItem {
Id = 3,
Name = "Butternut",
Description = "Butter with nut"
};
ElasticClient.Index(testItem3, "elastictesting", "TestItem", testItem3.Id);
Console.WriteLine("Write search phrase:");
var searchPhrase = Console.ReadLine();
var searchResults = Search(searchPhrase);
Console.WriteLine("Number of search results: " + searchResults.Count());
foreach (var item in searchResults) {
Console.WriteLine(item.Name);
Console.WriteLine(item.Description);
}
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
private static List<TestItem> Search(string searchPhrase)
{
var query = BuildQuery(searchPhrase);
var result = ElasticClient
.Search(query)
.Documents
.Select(d => d)
.Distinct()
.ToList();
return result;
}
public static ElasticClient ElasticClient
{
get
{
var localhost = new Uri("http://localhost:9200");
var setting = new ConnectionSettings(localhost);
setting.SetDefaultIndex("elastictesting");
return new ElasticClient(setting);
}
}
private static SearchDescriptor<TestItem> BuildQuery(string searchPhrase)
{
var searchDescriptor = new SearchDescriptor<TestItem>()
.Query(q => q
.MultiMatch(m =>
m.OnFields(new[] {
"name",
"description"
}).QueryString(searchPhrase).Type(TextQueryType.PHRASE_PREFIX)
)
)
.Index("elastictesting")
.Type("TestItem")
.Size(500);
var jsons = JsonConvert.SerializeObject(searchDescriptor, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
return searchDescriptor;
}
}
class TestItem {
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}
Instead of using FuzzyLikequery.. use prefix query its more fast and accurate..!
for more information refer
curl -XPOST "http://localhost:9200/try/indextype/_search" -d'
{
"query": {
"prefix": {
"field": {
"value": "Butter"
}
}
}
}'
create above query in NEST and try again..!
This has nothing to do with FuzzyLikeThis.
You can use prefixquery as suggested by #BlackPOP out of the box.
You could also opt for using EdgeNGrams, this will tokenize your input on index-time. The result faster performance as compared to prefixquery, offset against increased index size.
One thing to keep in mind is that prefixquery only works on non-analyzed fields, so if you want to do any anaylzing at indexing-time, you're probably better off using EdgeNGrams.
Please read up on anaylzers etc, if you don't know what they are.
Some refs:
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-analyzers.html
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-edgengram-tokenizer.html
See How can I do a prefix search in ElasticSearch in addition to a generic query string? for a similar question.

Replacing a method node using Roslyn

While exploring Roslyn I put together a small app that should include a trace statement as the first statement in every method found in a Visual Studio Solution. My code is buggy and is only updating the first method.
The line that is not working as expected is flagged with a “TODO” comment. Please, advise.
I also welcome style recommendations that would create a more streamlined/readable solution.
Thanks in advance.
...
private void TraceBtn_Click(object sender, RoutedEventArgs e) {
var myWorkSpace = new MyWorkspace("...Visual Studio 2012\Projects\Tests.sln");
myWorkSpace.InjectTrace();
myWorkSpace.ApplyChanges();
}
...
using System;
using System.Linq;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
using Roslyn.Services;
namespace InjectTrace
{
public class MyWorkspace
{
private string solutionFile;
public string SolutionFile {
get { return solutionFile; }
set {
if (string.IsNullOrEmpty(value)) throw new Exception("Invalid Solution File");
solutionFile = value;
}
}
private IWorkspace loadedWorkSpace;
public IWorkspace LoadedWorkSpace { get { return loadedWorkSpace; } }
public ISolution CurrentSolution { get; private set; }
public IProject CurrentProject { get; private set; }
public IDocument CurrentDocument { get; private set; }
public ISolution NewSolution { get; private set; }
public MyWorkspace(string solutionFile) {
this.SolutionFile = solutionFile;
this.loadedWorkSpace = Workspace.LoadSolution(SolutionFile);
}
public void InjectTrace()
{
int projectCtr = 0;
int documentsCtr = 0;
int transformedMembers = 0;
int transformedClasses = 0;
this.CurrentSolution = this.LoadedWorkSpace.CurrentSolution;
this.NewSolution = this.CurrentSolution;
//For Each Project...
foreach (var projectId in LoadedWorkSpace.CurrentSolution.ProjectIds)
{
CurrentProject = NewSolution.GetProject(projectId);
//..for each Document in the Project..
foreach (var docId in CurrentProject.DocumentIds)
{
CurrentDocument = NewSolution.GetDocument(docId);
var docRoot = CurrentDocument.GetSyntaxRoot();
var newDocRoot = docRoot;
var classes = docRoot.DescendantNodes().OfType<ClassDeclarationSyntax>();
IDocument newDocument = null;
//..for each Class in the Document..
foreach (var #class in classes) {
var methods = #class.Members.OfType<MethodDeclarationSyntax>();
//..for each Member in the Class..
foreach (var currMethod in methods) {
//..insert a Trace Statement
var newMethod = InsertTrace(currMethod);
transformedMembers++;
//TODO: PROBLEM IS HERE
newDocRoot = newDocRoot.ReplaceNode(currMethod, newMethod);
}
if (transformedMembers != 0) {
newDocument = CurrentDocument.UpdateSyntaxRoot(newDocRoot);
transformedMembers = 0;
transformedClasses++;
}
}
if (transformedClasses != 0) {
NewSolution = NewSolution.UpdateDocument(newDocument);
transformedClasses = 0;
}
documentsCtr++;
}
projectCtr++;
if (projectCtr > 2) return;
}
}
public MethodDeclarationSyntax InsertTrace(MethodDeclarationSyntax currMethod) {
var traceText =
#"System.Diagnostics.Trace.WriteLine(""Tracing: '" + currMethod.Ancestors().OfType<NamespaceDeclarationSyntax>().Single().Name + "." + currMethod.Identifier.ValueText + "'\");";
var traceStatement = Syntax.ParseStatement(traceText);
var bodyStatementsWithTrace = currMethod.Body.Statements.Insert(0, traceStatement);
var newBody = currMethod.Body.Update(Syntax.Token(SyntaxKind.OpenBraceToken), bodyStatementsWithTrace,
Syntax.Token(SyntaxKind.CloseBraceToken));
var newMethod = currMethod.ReplaceNode(currMethod.Body, newBody);
return newMethod;
}
public void ApplyChanges() {
LoadedWorkSpace.ApplyChanges(CurrentSolution, NewSolution);
}
}
}
The root problem of you code is that newDocRoot = newDocRoot.ReplaceNode(currMethod, newMethod); somehow rebuilds newDocRoot internal representation of code so next currMethod elements won't be find in it and next ReplaceNode calls will do nothing. It is a situation similar to modifying a collection within its foreach loop.
The solution is to gather all necessary changes and apply them at once with ReplaceNodes method. And this in fact naturally leads to simplification of code, because we do not need to trace all those counters. We simply store all needed transformation and apply them for whole document at once.
Working code after changes:
public void InjectTrace()
{
this.CurrentSolution = this.LoadedWorkSpace.CurrentSolution;
this.NewSolution = this.CurrentSolution;
//For Each Project...
foreach (var projectId in LoadedWorkSpace.CurrentSolution.ProjectIds)
{
CurrentProject = NewSolution.GetProject(projectId);
//..for each Document in the Project..
foreach (var docId in CurrentProject.DocumentIds)
{
var dict = new Dictionary<CommonSyntaxNode, CommonSyntaxNode>();
CurrentDocument = NewSolution.GetDocument(docId);
var docRoot = CurrentDocument.GetSyntaxRoot();
var classes = docRoot.DescendantNodes().OfType<ClassDeclarationSyntax>();
//..for each Class in the Document..
foreach (var #class in classes)
{
var methods = #class.Members.OfType<MethodDeclarationSyntax>();
//..for each Member in the Class..
foreach (var currMethod in methods)
{
//..insert a Trace Statement
dict.Add(currMethod, InsertTrace(currMethod));
}
}
if (dict.Any())
{
var newDocRoot = docRoot.ReplaceNodes(dict.Keys, (n1, n2) => dict[n1]);
var newDocument = CurrentDocument.UpdateSyntaxRoot(newDocRoot);
NewSolution = NewSolution.UpdateDocument(newDocument);
}
}
}
}

Categories

Resources