Sparx EA.App doesn't reflect Activator.CreateInstance properly - c#

I've got .NET Framework 4.6.2 console app that is accessing Sparx Enterprise Architect repository. The code below shows a simple example of using Activator.CreateInstance(). The problem is that when creating a second instance the current one (stored in eaApp) is used, so I cannot access two different repositories. Is there any witted solution to this problem?
static void Main(string[] args)
{
EA.App eaApp = (EA.App)Activator.CreateInstance(Type.GetTypeFromProgID("EA.App", true));
EA.App eaApp2 = (EA.App)Activator.CreateInstance(Type.GetTypeFromProgID("EA.App", true));
eaApp.Repository.OpenFile(#"c:\Temp\UCI2.EAP");
eaApp2.Repository.OpenFile(#"c:\Temp\UCI3.EAP");
EA.Element test = eaApp.Repository.GetElementByGuid("{53F2ADAE-E8AC-40da-A06F-D64F525B87E8}");
EA.Element test2 = eaApp2.Repository.GetElementByGuid("{DBF0459F-0662-4e5b-B7E3-A065087B624E}");
Console.WriteLine($"test1: {test.Notes} test2: {test2.Notes}");
Console.ReadKey();
}

If you want to create a new instance do something like this
EA.Repository r = new EA.Repository();
r.OpenFile("c:\\eatest.eap");
As described in the manual
Connecting to the (first) running instance can be done like this:
using System.Runtime.InteropServices;
...
object obj = Marshal.GetActiveObject("EA.App");
var eaApp = obj as EA.App;
var myRepository = eaApp?.Repository;

Related

Has there been an update to C# on Visual Studio or is it just my IDE?

I logged onto my Visual Studio and started to make some unit tests for a project and I noticed that in order to make an instance of a class from another project (my main project) I have to add the the namespace before the class. It wasn't like this yesterday. It's kind of bugging me. So was there an update overnight or did I change something in my IDE?
var foo = new Something.Something(); // <-- This is what I have to do now in projects
var foo = new Something(); // <-- This is what I was doing for the past year
If it is just me could you tell me how to fix this.
var g1 = new GradeBook.GradeBook();
var g2 = g1;
g1 = new GradeBook.GradeBook();
g1.Name = "Jakub's GradeBook";
Assert.AreEqual(g1.Name, g2.Name);
If I get rid of the GradeBook namespace the compiler throws out an error.
var g1 = new GradeBook();
var g2 = g1;
g1 = new GradeBook();
g1.Name = "Jakub's GradeBook";
Assert.AreEqual(g1.Name, g2.Name);
When I add a using directive it still throws out errors - missing reference in file
The problem is, that both your class and its namespace have the same name.
Making the compiler unable to tell which one you are referring to. Hence you'll get an error similiar like GradeBook is a namespace but is used like a type
It should work if you write
var x = new GradeBook.GradeBook();
You can work arround this by using an alias for your using like so:
using G=GradeBook;
And then write
var x = new G.GradeBook();
But I`d recommend you to reevaluate your naming.
No.
I think you are missing the namespace to your project containing Something() class.
Import your project as follow:
using Something;
And then you will be able to use your class without having to add the project name before it, like:
var foo = new Something();

How would one simulate proxy functions without the HttpListener or TCPListener components in C#?

How can I simulate the functions/actions of a proxy server but without calling elements like HttpListener or TcpListener? How can I generate them from within my C# application?
I've been able to get as far as getting actual data streamed back to my WebBrowser element in my C# application but upon viewing the results, it gives me errors. The reason being is because I'm viewing the LITERAL string and there are JS/CSS components within the resulting HTML stream that makes references to objects via relative URIs. Obviously, my solution thinks they're local and, as such, can't resolve them.
I'm missing proxy-like functions where it should just hand off the stream back to my mock browser and display properly. However, looking at sample proxy server codes built on C#, they're all built as servers using listeners. I'd like it to be something that I can instantiate locally without the need to create a listening interface.
Now, you may be wondering why I'm trying to do this? Well, there are a couple of reasons:
To be able to inject headers ad-hoc so I can test internal web servers
To run as a headless (no GUI) component that can take either HTTP or HTTPS streams from other .NET components and inject headers from, yet, other .NET components.
Some other back-end stuff that I think might but won't know until I have this in place.
Here's what I have so far:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using HtmlAgilityPack;
using System.Net;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
WebClient client = new WebClient();
var baseUrl = new Uri(textBox1.Text);
client.Headers.Add("Token1", textBox2.Text);
client.Headers.Add("Token2",textBox3.Text);
byte[] requestHTML = client.DownloadData(textBox1.Text);
string sourceHTML = new UTF8Encoding().GetString(requestHTML);
HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();
htmlDoc.LoadHtml(sourceHTML);
//"//*[#background or #lowsrc or #src or #href]"
foreach (HtmlNode link in htmlDoc.DocumentNode.SelectNodes("//*[#href]"))
{
//Console.Out.WriteLine(link.ToString());
if (!string.IsNullOrEmpty(link.Attributes["href"].Value))
{
HtmlAttribute att = link.Attributes["href"];
Console.WriteLine("Before: " + att.Value);
//Console.Out.WriteLine(att.Value.ToString());
Console.WriteLine(new Uri(baseUrl, att.Value));
link.Attributes["href"].Value = new Uri(baseUrl, att.Value).ToString();
Console.WriteLine("After: " + link.Attributes["href"].Value);
//att.Value = this.AbsoluteUrlByRelative(att.Value);
}
}
foreach (HtmlNode link2 in htmlDoc.DocumentNode.SelectNodes("//*[#src]"))
{
//Console.Out.WriteLine(link.ToString());
if (!string.IsNullOrEmpty(link2.Attributes["src"].Value))
{
HtmlAttribute att = link2.Attributes["src"];
Console.WriteLine("Before: " + att.Value);
// //Console.Out.WriteLine(att.Value.ToString());
Console.WriteLine(new Uri(baseUrl, att.Value));
if (!att.Value.Contains("/WS"))
{
Console.WriteLine("HIT ME!");
var output = "/WS/" + att.Value;
link2.Attributes["src"].Value = new Uri(baseUrl, output).ToString();
Console.WriteLine("After HIT: " + link2.Attributes["src"].Value);
}
else
{
link2.Attributes["src"].Value = new Uri(baseUrl, att.Value).ToString();
Console.WriteLine("After: " + link2.Attributes["src"].Value);
}
// //att.Value = this.AbsoluteUrlByRelative(att.Value);
}
}
Console.WriteLine(htmlDoc.DocumentNode.OuterHtml);
Console.WriteLine("+========================+");
webBrowser1.DocumentText = htmlDoc.DocumentNode.OuterHtml;
}
}
}
Again, this is just prototyped code so forgive the wacky spacing and commenting. In the end, it will be more formal. Right now, this monkey is killing my back.
How about using something like NMock or similar? It would mean having to introduce interfaces so that the mocks can be injected, but still beats doing it almost any other way, IMHO...
From the NMock site:
NMock is a dynamic mock object library for .NET. Mock objects make it
easier to test single components—often single classes—without relying
on real implementations of all of the other components. This means we
can test just one class, rather than a whole tree of objects, and can
pinpoint bugs much more clearly. Mock objects are often used during
Test Driven Development.
You would mock the proxy server more or less like this:
var mocks = new Mockery();
var mockProxyServer = mocks.NewMock<IMyProxyServer>();
That's all you need to do. As you can see, it's interface-dependent. But usually all that I've needed to do is Refactor->Extract Interfaces from the relevant class in VS.
Setting up the simulation is usually done within the context of the unit test, like:
public class TransferFundsPresenterTest
{
private Mockery mocks;
private IMyProxyServer mockProxyServer
[SetUp]
public void SetUp()
{
mocks = new Mockery();
mockProxyServer = mocks.NewMock<IMyProxyServer>();
}
[Test]
public void TestProxyFunction()
{
Expect.Once.On(mockProxyServer).
Method("ProxyFunctionA").
With("1234"). // <-- simulate the input params here
Will(Return.Value("Test")); // <-- simulate the output from server here
}
This is just a basic example. You can do a lot more, it's a very flexible library.
You really should take a look at the NMock site, it's pretty easy to get fully up to speed with the library.
http://www.nmock.org/index.html

Building programmatically a project

I need to build a project programmatically for a .csproj I am creating on the fly.
While searching Google I found the classes and API provided by the MS for the MSBuild Engine. With that information, I create a process which executes msbuild.exe and then reads the output, but now I want to use the namespace Microsoft.Build.Execution to build the project. This is my program:
public class Compiler
{
private static string locationOfMSBuilldEXE = "";
public static void Build(string msbuildFileName)
{
BuildManager manager = BuildManager.DefaultBuildManager;
ProjectInstance projectInstance = new ProjectInstance(msbuildFileName);
var result = manager.Build(new BuildParameters()
{
DetailedSummary = true
},
new BuildRequestData(projectInstance, new string[] { "Build" }));
var buildResult = result.ResultsByTarget["Build"];
var buildResultItems = buildResult.Items;
string s = "";
}
}
The results show that this is building fine, but I need to know the detailed output from the compile and how to view it. It would be really helpful if someone can give me link to a good tutorial or a book on MSBuild.
Thanks #ritchmelton. Though I figured it out myself.
Here is my code : I have used an in built logger ConsoleLogger
public class Compiler
{
private static string locationOfMSBuilldEXE = "";
public static void Build(string msbuildFileName)
{
ConsoleLogger logger = new ConsoleLogger(LoggerVerbosity.Normal);
BuildManager manager = BuildManager.DefaultBuildManager;
ProjectInstance projectInstance = new ProjectInstance(msbuildFileName);
var result = manager.Build(
new BuildParameters()
{
DetailedSummary = true,
Loggers = new List<ILogger>(){logger}
},
new BuildRequestData(projectInstance, new string[] { "Build" }));
var buildResult = result.ResultsByTarget["Build"];
var buildResultItems = buildResult.Items;
string s = "";
}
}
You need to add a instance of a class that implements the ILogger interface to your BuildParameters. You can add a new instance of one of the supplied loggers in the Microsft.Build.Logging namespace, or you can implement ILogger yourself as it is very small and there is a helper class in the Microsoft.Build.Utilities namespace called Logger that is easy to extend.
Build loggers
ILogger interface
Logger helper
If you just want to build a project or solution, without elaborate parameters, you can do it more simply. Pseudocode:
using namespace Microsoft.Build.Evaluation;
var p = Project.Load("path to project");
p.SetGlobalProperty("Configuration", "Release");
p.Build(...);
That's it! BuildParameters and so forth are for quite advanced scenarios. Visual Studio itself uses them.
Dan (msbuild dev)

c# create an instance of an object from string

I have a string variable contain:
string classCode = "public class Person { public string Name{get;set;} }";
How can I create an instance of an object from the classCode ?
like
object obj = CreateAnInstanceAnObject(classCode);
You'll need to use CodeDom to compile an in-memory assembly, and then use reflection to create the type.
Here's a sample article on MSDN that walks through the process of code generation.
Once you've compiled the code, you can use Activator.CreateInstance to create an instance of it.
Building on the answers from above, here is a working demo to generate, compile and instantiate a class from an in-memory assembly:
namespace DynamicCompilation
{
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
internal static class Program
{
private static void Main()
{
var ccu = new CodeCompileUnit();
var cns = new CodeNamespace("Aesop.Demo");
cns.Imports.Add(new CodeNamespaceImport("System"));
var ctd = new CodeTypeDeclaration("Test")
{
TypeAttributes = TypeAttributes.Public
};
var ctre = new CodeTypeReferenceExpression("Console");
var cmie = new CodeMethodInvokeExpression(ctre, "WriteLine", new CodePrimitiveExpression("Hello World!"));
var cmm = new CodeMemberMethod
{
Name = "Hello",
Attributes = MemberAttributes.Public
};
cmm.Statements.Add(cmie);
ctd.Members.Add(cmm);
cns.Types.Add(ctd);
ccu.Namespaces.Add(cns);
var provider = new CSharpCodeProvider();
var parameters = new CompilerParameters
{
CompilerOptions = "/target:library /optimize",
GenerateExecutable = false,
GenerateInMemory = true
};
////parameters.ReferencedAssemblies.Add("System.dll");
var results = provider.CompileAssemblyFromDom(parameters, ccu);
if (results.Errors.Count == 0)
{
var t = results.CompiledAssembly.GetType("Aesop.Demo.Test");
var inst = results.CompiledAssembly.CreateInstance("Aesop.Demo.Test");
t.InvokeMember("Hello", BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, inst, null);
}
Console.ReadLine();
}
}
}
Simple put you cannot do this in one line as you are attempting. It is possible to create an instance of an existing class via it's name and one of the overloads of Activator.CreateInstance.
What you are trying to achieve here though is quite different. You are attempting to both 1) define a new class type and 2) create an instance of it. Defining new metadata in the running process dynamically is very difficult to achieve with static languages like C#. It requires a significant amount of work that can't easily be put into a StackOverflow answer.
The following project should guide you in what your trying to accomplish:
RunTime Code Compilation
However, if you are attempting to write code at runtime, you may want to rethink your architecture. You may be creating more of a headache for yourself than you need to be.
What are you trying to accomplish by creating this object?

How do I create an XTextTable in OpenOffice.org uno using C#?

Discussion on OOoForum.org
In python, using pyuno, I can do it like this:
table = self.model.createInstance("com.sun.star.text.TextTable")
This doesn't seem to work in C#. Here is my test code (I realize I probably don't need all those using statements, but I am adapting someone else's code):
using System;
using unoidl.com.sun.star.lang;
using unoidl.com.sun.star.uno;
using unoidl.com.sun.star.bridge;
using unoidl.com.sun.star.frame;
using unoidl.com.sun.star.document;
using unoidl.com.sun.star.text;
using unoidl.com.sun.star.container;
using unoidl.com.sun.star.util;
using unoidl.com.sun.star.table;
using unoidl.com.sun.star.beans;
namespace FromScratch
{
class MainClass
{
public static void Main(string[] args)
{
XComponentContext componentContext =
uno.util.Bootstrap.bootstrap();
XMultiServiceFactory multiServiceFactory = (XMultiServiceFactory)
componentContext.getServiceManager();
XTextDocument document;
XComponentLoader loader = (XComponentLoader)
multiServiceFactory.createInstance
("com.sun.star.frame.Desktop");
document = (XTextDocument) loader.loadComponentFromURL
("private:factory/swriter", "_blank", 0,
new PropertyValue[0]);
XText text = document.getText();
XTextCursor cursor = text.createTextCursor();
XTextTable table = (XTextTable)
multiServiceFactory.createInstance
("com.sun.star.text.TextTable");
table.initialize(2, 2);
text.insertTextContent(cursor, table, false);
}
}
}
Most of it seems to work fine, but when it gets to this line:
table.initialize(2, 2);
I get a runtime error:
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object
at FromScratch.MainClass.Main (System.String[] args) [0x00063] in /home/matthew/Desktop/OpenOfficeSample/FromScratch/Main.cs:37
Apparently, this line:
XTextTable table = (XTextTable)
multiServiceFactory.createInstance
("com.sun.star.text.TextTable");
doesn't actually set table to anything.
What is going on here?
Solution (from OOoForum.org):
You must get the text table from the document multiservice factory, not from the multiservice factory of the service manager. You can do this by casting your document (a Model) to XMultiServiceFactory and calling its createInstance method.
XTextTable table = (XTextTable)
((XMultiServiceFactory)document).createInstance
("com.sun.star.text.TextTable");
See DevGuide.

Categories