I am trying to use a service created by somebody else. I have only the service dll. But the instructions provided to me are not complete. This is an example how to use the service but they missed the instantiation of the variable criteria. How can I figure out what type is the variable? . If possible, I prefer to solve the issue without decompiling the dll.
public static void GetData()
{
//ServiceReference1.ServicesClient client = null;
try
{
criteria.Settings = new CheckCall.CriteriaSettings();
CheckCall.Criteria criteria1 = new CheckCall.Criteria();
criteria1.Settings = new CheckCall.CriteriaSettings();
criteria1.AsgnType = CheckcallAssignTypeEnum.Driver;
criteria1.TractorNumber = "Tractor1";
criteria.Expressions = new List<CheckCall.CriteriaExpression>();
criteria.Expressions.Add(new CheckCall.CriteriaExpression
{
Conjuction = CriteriaSetting.ConjuctionEnum.OrOp,
Criteria = criteria1
});
}
catch(Exception ex)
{
Console.Write(ex);
}
}
You could use JetBrains .Net decompiler - dotPeek.(https://www.jetbrains.com/decompiler/)
Decompile the dll, then add the decompiled project to your solution and debug it. The only problem is wether you will receive a project that can be built after decompilation
If the decompilation is not an option/project has errors after decompilation - you can see the contents of the .dll via Object Browser. Find the .dll in the References, right click on it and choose "View in Object Browser". You will see the namespaces, classes and their methods of the .dll. Enter any of the property names of criteria object (Settings or Expressions) and Object Browser will filter everything out
Related
I have a c# library which provides some functionallity to upload data onto connected (android) devices. The dll itself gets exported via UnmangedExports to be used by an delphi application.
Here is the function which gets called by the delphi application:
[DllExport]
[return: MarshalAs(UnmanagedType.LPStr)]
public static string getDevices()
{
try
{
var devices = string.Empty;
var collection = new PortableDeviceCollection();
collection.Refresh();
foreach (var device in collection)
{
device.Connect();
if (devices != string.Empty)
{
devices += ";";
}
devices += device.FriendlyName;
device.Disconnect();
}
return devices;
}
catch (Exception e)
{
SomeClass.WriteErrorToLogFile(e);
return "ERROR";
}
}
Here is the class PortableDeviceCollection:
public class PortableDeviceCollection : Collection<PortableDevice>
{
private readonly PortableDeviceApiLib.PortableDeviceManagerClass _deviceManager;
public PortableDeviceCollection()
{
this._deviceManager = new PortableDeviceApiLib.PortableDeviceManagerClass();
}
public bool Refresh()
{
this._deviceManager.RefreshDeviceList();
// Determine how many WPD devices are connected
var deviceIds = new string[1];
uint count = 1;
this._deviceManager.GetDevices(null, ref count);
if (count > 0)
{
// Retrieve the device id for each connected device
deviceIds = new string[count];
this._deviceManager.GetDevices(deviceIds, ref count);
foreach (var deviceId in deviceIds)
{
Add(new PortableDevice(deviceId));
}
return true;
}
else
return false;
}
}
I can create the dll with visual studio and use this inside of the delphi application. When the delphi application calls the getDevices() function, i get an error on the instantiation of the PortableDeviceCollection class:
The file or assembly "Interop.PortableDeviceApiLib, Version = 1.0.0.0,
Culture = neutral, PublicKeyToken = null" or a dependency of it was
not found. The assembly is created by a runtime that is more recent
than the currently loaded runtime and can not be loaded.
ProductXY.PortableDeviceCollection..ctor()
ProductXY.ProductXYMain.getDevices()
The targetframework for the c# project is set to .Net Framework 4. Using any lower version i get an error when i try to compile the project:
The primary reference "Interop.PortableDeviceApiLib" could not be
resolved because it has an indirect dependency on the .NET Framework
assembly "mscorlib, version = 4.0.0.0, Culture = neutral,
PublicKeyToken = b77a5c561934e089", which is a higher version 4.0.0.0
than version 2.0.0.0 in the current target framework.
Please note. I have neither written the c# library nor the delphi application. Both have worked together for years. Now i have to add a functionallity to the c# library. I have not added any code to the project. I just tried to compile it again and use the dll. The only thing i did was updating the RGiesecke.DLLExport.Metadata via NuGet Packetmanager. Without updating i got an error
"Microsoft.Build.Utilities.ToolLocationHelper could not find
ildasm.exe"
I am aware of this Enumerating Windows Portable Devices in C# question. But my error is thrown before the code which is treaded by the question is reached. I still tried the solution to the question, but the action (deassamble, find and replace in the dll) which is described in the answere has already been done (otherwise my code would not have compiled).
The error message doesn't make sense to me. Interop.PortableDeviceApiLib is a COM-Lib which is not available for download in different framework-versions. I think I am missing something here.
Can anyone help me?
I was finally able to solve this problem. To be honest I don't know what finally solved this. For every one who stumbles up on this, here are the things i tried to fix this problem. They are in no specific order (since i tried everything multiple times):
Updating the RGiesecke.DLLExport packet
Changing the plattform in the Konfigurations-Manager to x86
Disassamble, edit and reassable the Interop.PortableDeviceApiLib like in this question (answeres of Christophe Geers and Bruno Klein)
Delete the reference to the Interop.PortableDeviceApiLib
Delete the reference to the Interop.PortableDeviceTypesLib
Readding the reference to the Interop.PortableDeviceApiLib
Readding the reference to the Interop.PortableDeviceTypesLib
Rebuild the project
Setting the Interoptyp embeddet on both to false (I found various statements to NOT do this, but the project was set up like this when i got it and it worked (be carefull)) on both Interop-Libs.
At least this helped me.
I'm actually integrating the amazing RoslynPad into a WinForms application and working damn well.
The point of the integration is allowing the user to type in some C# code so it can be used in a future.
Thing is I'm interested on "capping" the user so he could just use some System or even LinQ functions. I don't want to allow the user to think he is allowed to use System.IO and others. Of course I can't prevent him/her typing System.IO.File.Delete, but will surely help if the System.IO's Assembly is not loaded into the RoslynPad's IntelliSense.
The source code typed by the user is going to be compiled locally before being saved into the DB. I'm adding just a few and necessary Assemblies for the compilation, so if System.IO it won't compile, of course.
As I explained, I just want to cap the Intellisense, so they don't think they have access to almost the whole .NET Framework.
EDIT: Added the actual implementation actually done. I'm loading "RoslynPad.Roslyn.Windows" and "RoslynPad.Editor.Windows" assemblies to the editor.
private RoslynCodeEditor _editor;
private void InitializeEditor(string sourceCode)
{
if (string.IsNullOrWhiteSpace(sourceCode))
sourceCode = string.Empty;
_editor = new RoslynCodeEditor();
var workingDirectory = Directory.GetCurrentDirectory();
var roslynHost = new RoslynHost(additionalAssemblies: new[]
{
Assembly.Load("RoslynPad.Roslyn.Windows"),
Assembly.Load("RoslynPad.Editor.Windows")
});
_editor.Initialize(roslynHost, new ClassificationHighlightColors(), workingDirectory, sourceCode);
_editor.FontFamily = new System.Windows.Media.FontFamily("Consolas");
_editor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#");
_editor.FontSize = 12.75f;
elementHost1.Child = _editor;
this.Controls.Add(elementHost1);
}
You can use pass a RoslynHostReferences instance to the RoslynHost constructor, and decide which assemblies and namespaces are imported by default.
You could use the same logic as Default, just remove System.IO.Path from the type list.
Note that System.IO is not an assembly, but rather a namespace, which is in the core library, so there's no simple way to completely remove it.
I need to compile source code of big project dynamically and output type can be Windows Application or Class Library.
Code is nicely executed and its possible to make .dll or .exe files, but problem is that, when I'm trying to make .exe file - it's losing resources like project icon. Result file doesn't include assembly information to.
Any way to solve this? (Expected result should be the same, that manual Build function on project file in Visual Studio 2015).
Thank you!
var workspace = MSBuildWorkspace.Create();
//Locating project file that is WindowsApplication
var project = workspace.OpenProjectAsync(#"C:\RoslynTestProjectExe\RoslynTestProjectExe.csproj").Result;
var metadataReferences = project.MetadataReferences;
// removing all references
foreach (var reference in metadataReferences)
{
project = project.RemoveMetadataReference(reference);
}
//getting new path of dlls location and adding them to project
var param = CreateParamString(); //my own function that returns list of references
foreach (var par in param)
{
project = project.AddMetadataReference(MetadataReference.CreateFromFile(par));
}
//compiling
var projectCompilation = project.GetCompilationAsync().Result;
using (var stream = new MemoryStream())
{
var result = projectCompilation.Emit(stream);
if (result.Success)
{
/// Getting result
//writing exe file
using (var file = File.Create(Path.Combine(_buildPath, fileName)))
{
stream.Seek(0, SeekOrigin.Begin);
stream.CopyTo(file);
}
}
}
We never really designed the workspace API to include all the information you need to emit like this; in particular when you're calling Emit there's an EmitOptions you can pass that includes, amongst other things, resource information. But we don't expose that information since this scenario wasn't hugely considered. We've done some of the work in the past to enable this but ultimately never merged it. You might wish to consider filing a bug so we officially have the request somewhere.
So what can you do? I think there's a few options. You might consider not using Roslyn at all but rather modifying the project file and building that with the MSBuild APIs. Unfortunately I don't know what you're ultimately trying to achieve here (it would help if you mentioned it), but there's a lot more than just the compiler invocation that is involved in building a project. Changing references potentially changes other things too.
It'd also be possible, of course, to update MSBuildWorkspace yourself to pass this through. If you were to modify the Roslyn code, you'll see we implement a series of interfaces named "ICscHostObject#" (where # is a number) and we get passed the information from MSBuild to that. It looks like we already stash that in the command line arguments, so you might be able to pass that to our command line parser and get the data back you need that way.
this question follows my previous question.
I have a c# ASP.NET application and i want to provide support for plugins. Plugins can be custom c# classes, javascript, html, css, images, etc.
I see no problem as long as my application is extended with c# classes because all the user has to do is create a new "class library" project in visual studio and implement the interfaces, i provide. Then build a dll out of it and upload it to my server. The plugin-developer can add static files (html, js, css, etc.) into this project as well but i found some problems with that:
Every static file i add to the plugin project gets the build action "content" and it seems i cannot read those files from my server. (see my previously answered question). I have to manually select "Embedded Resource" on each file, so it is packed with the plugin dll.
I want to support Typescript for the plugins. The Typescript compiler generates javascript files in the same directory as the typescript-files. But the javascript files are not included in the project and therefore i have to include these in the plugin project and then set the correct build action. I don't want the plugin developers to do that all the time.
If the static files have the build action "enbedded resources", then the server can pickup these files by using the assembly.GetManifestResourceNames() method. This method returns the resources as a string. The path is not separated by \ or / but with a dot instead. So i am not able to distinguish between file path (this is relevant) or filename (also relevant to pickup the correct files), because the original filename can also have dots.
So i am starting to question the "class library" project type is right for my needs. Is there a way to get around of my issues or do i have to use another project type?
Thank you for any help!
Edit: Changed the question a little bit so it is better to understand.
You could make a zip package with the plugin dll and files. NuGet also uses this mechanism. A .nupkg is also just a zip file.
I would start by looking at MEF (Managed Extensibility Framework).
MSDN information can be found here: https://msdn.microsoft.com/en-us/library/dd460648(v=vs.110).aspx
From that link you can get more information and I believe there is a tutorial as well.
Oh, for me it seems very simple.
Let the developer create the plugin freestyle and put all the additional files in a directory, let's call it extras
To implement the your interface they will need your assembly so I guess you will ship it via nuget, or just some link. No matter what the case, provide them with some powershell script what will be required to run before the final build
The script would create zip archive from the extras directory and add it to the ClassLibrary project as EmbeddedResource.
As you mentioned earlier, you can access EmbeddedResource. So all you would do is to unpack it and you would have the exact directory tree.
The best idea would be to provide project template with script included, and also the empty zip archive added as embedded resource (it will be easier to just pack the files in the script and replace the file), and pre-build action set to run the script.
Am I missing something?
What about this.
In your web application, you could add a function that loop into your plugin directory and find DLL implementing an Iplugin (name is up to you) interface.
The interface is defined in a class library that both your web application and plugins have to implement.
You can use the Httpcontext Server mappath to read javascript and other files.
Here is a very basic implementation
First, you have the plugin interface (a class library implemented both by the web application and the individual plugins) I implemented sample properties and methods...
using System.Web;
public interface IPlugin
{
string Name { get; set; }
string Output { get; set; }
void Load(ref httpcontext Context);
void Dispose();
void Display();
}
Next, you have the Actual plugin class library we want to implement.
using System.Web;
using IPlugins;
public class AwesomePlugin : IPlugins.IPlugin
{
private string _Name = "AwesomePlugin";
private HttpContext _Context;
public string Name {
get { return _Name; }
set { _Name = value; }
}
public string Output {
get { return "Yay !!!"; }
set {
throw new NotImplementedException();
}
}
public void Display()
{
throw new NotImplementedException();
}
public void Dispose()
{
throw new NotImplementedException();
}
public void Load(ref Web.HttpContext Context)
{
}
}
Finally, you dynamically load your plugins so you can use them in your application.
private Dictionary<string, IPlugins.IPlugin> _Plugins = new Dictionary<string, IPlugins.IPlugin>();
public void LoadPlugins()
{
lock (static_LoadPlugins_IpluginType_Init) {
try {
if (InitStaticVariableHelper(static_LoadPlugins_IpluginType_Init)) {
static_LoadPlugins_IpluginType = typeof(IPlugins.IPlugin);
}
} finally {
static_LoadPlugins_IpluginType_Init.State = 1;
}
}
string ServerPath = HttpContext.Current.Server.MapPath("~") + "Plugins";
dynamic Plugins = io.Directory.GetFiles(ServerPath);
foreach (string PluginPath in Plugins) {
dynamic Assembly = system.Reflection.Assembly.LoadFile(PluginPath);
Type PluginClass = Assembly.GetTypes.Where(T => T.GetInterface("IPlugin") != null).First;
IPlugins.IPlugin MyPlugin = Activator.CreateInstance(PluginClass);
MyPlugin.Load(httpcontext.Current);
_Plugins.#add(PluginClass.ToString, MyPlugin);
}
}
static bool InitStaticVariableHelper(Microsoft.VisualBasic.CompilerServices.StaticLocalInitFlag flag)
{
if (flag.State == 0) {
flag.State = 2;
return true;
} else if (flag.State == 2) {
throw new Microsoft.VisualBasic.CompilerServices.IncompleteInitialization();
} else {
return false;
}
}
That way, you can implement whatever you want in your plugin.
I believe you could load your plugins in a separate appdomain with restricted permissions to everything.
The files (Javascript / CSS / Html) should be available by accessing the full path of the file.
string ServerPath = HttpContext.Current.Server.MapPath("~") + "Plugins";
If the resources is embedded into the plugin DLL, you could read the stream from the loaded assembly or let the plugin manage its own embedded files.
For question Number 2, you can use
MS Build
to change the contenttype during build process.
You have to make yourself confident with MS Build
I'm looking for a method that let's me validate code and generator code as part of the build process, using Visual Studio 2010 (not express) and MSBuild.
Background Validation:
I'm writing a RESTful web service using the WCF Web Api. Inside the service class that represents the web service I have to define an endpoint, declaring additionally parameters as plain test. When the parameter name inside the endpoint declaration differs from the parameter of the C# method I get a error - unfortunately at run time when accessing the web service, not at compile time. So I thought it would be nice to analyze the web service class as part of the compile step for flaws like this, returning an error when something is not right.
Example:
[WebGet(UriTemplate = "Endpoint/{param1}/{param2}")]
public string MyMethod(string param1, string parameter2) {
// Accessing the web service now will result in an error,
// as there's no fitting method-parameter named "param2".
}
Also I'd like to enforce some naming rules, such as GET-Methods must start with the "Get" word. I believe this will help the service to remain much more maintainable when working with several colleagues.
Background Generation:
I will be using this REST web service in a few other projects, there for I need to write a client to access this service. But I don't want to write a client for each of these, always adjusting whenever the service changes. I'd like the clients to be generated automatically, based upon the web service code files.
Previous approach:
So far I tried to use a T4 template using the DTE interface to parse the code file and validate it, or generate the client. This worked fine in Visual Studio when saving manually, but integrating this in the build process turned out to be not so working well, as the Visual Studio host is not available using MSBuild.
Any suggestion is welcome. :)
Instead of using DTE or some other means to parse the C# code you could use reflection (with Reflection-Only context) to examine the assembly after it's compiled. Using reflection is a more robust solution and probably faster also (especially if you use Mono.Cecil to do the reflecting).
For the MSBuild integration I would recommend writing a custom MSBuild task - it's fairly easy and more robust/elegant than writing a command line utility that's executed by MSBuild.
This may be a long shot but still qualifies as "any suggestion" :)
You could compile the code, then run a post-build command which would be a tool that you'd have to write which uses reflection to compare the parsed UriTemplate text with the method parameter names, catching errors and outputting them in a manner that MSBuild will pickup. Look at This Link for information on how to output so MSBuild will put the errors in the visual studio error list. The post-build tool could then delete the compiled assemblies if errors were found, thus "simulating" a failed build.
Here's the SO Link that lead me to the MSBuild Blog too, just for reference.
HTH
For the enforcement side of things, custom FxCop rules would probably be a very good fit.
For the client code generation, there are quite a few possibilities. If you like the T4 approach, there is probably a way to get it working with MSBuild (but you would definitely need to provide a bit more detail regarding what isn't working now). If you're want an alternative anyway, a reflection-based post-build tool is yet another way to go...
Here is a short, extremely ugly program that you can run over an assembly or group of assemblies (just pass the dlls as arguments) to perform the WebGet UriTemplate check. If you don't pass anything, it runs on itself (and fails, appropriately, as it is its own unit test).
The program will print out to stdout the name of the methods that are missing the parameters and the names of the missing parameters, and if any are found, will return a non-zero return code (standard for a program failing), making it suitable as a post-build event. I am not responsible if your eyes bleed:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.ServiceModel.Web;
namespace ConsoleApplication1
{
class Program
{
static int Main(string[] args)
{
var failList = new ConcurrentDictionary<MethodInfo, ISet<String>>();
var assembliesToRunOn = (args.Length == 0 ? new[] {Assembly.GetExecutingAssembly()} : args.Select(Assembly.LoadFrom)).ToList();
assembliesToRunOn.AsParallel().ForAll(
a => Array.ForEach(a.GetTypes(), t => Array.ForEach(t.GetMethods(BindingFlags.Public | BindingFlags.Instance),
mi =>
{
var miParams = mi.GetParameters();
var attribs = mi.GetCustomAttributes(typeof (WebGetAttribute), true);
if (attribs.Length <= 0) return;
var wga = (WebGetAttribute)attribs[0];
wga.UriTemplate
.Split('/')
.ToList()
.ForEach(tp =>
{
if (tp.StartsWith("{") && tp.EndsWith("}"))
{
var tpName = tp.Substring(1, tp.Length - 2);
if (!miParams.Any(pi => pi.Name == tpName))
{
failList.AddOrUpdate(mi, new HashSet<string> {tpName}, (miv, l) =>
{
l.Add(tpName);
return l;
});
}
}
});
})));
if (failList.Count == 0) return 0;
failList.ToList().ForEach(kvp => Console.Out.WriteLine("Method " + kvp.Key + " in type " + kvp.Key.DeclaringType + " is missing the following expected parameters: " + String.Join(", ", kvp.Value.ToArray())));
return failList.Count;
}
[WebGet(UriTemplate = "Endpoint/{param1}/{param2}")]
public void WillPass(String param1, String param2) { }
[WebGet(UriTemplate = "Endpoint/{param1}/{param2}")]
public void WillFail() { }
[WebGet(UriTemplate = "Endpoint/{param1}/{param2}")]
public void WillFail2(String param1) { }
}
}