For compatibility reasons between out legacy ASP code and new ASP.NET code, we have a bunch of .NET COM object that expose some of our .NET utilities to the ASP. In some cases we need to work with another COM objects inside of our .NET COM wrappers. To allow high flexibility and avoid PIA dependencies, we decided to use dynamic code to work with those COM objects.
Simplified C# COM object:
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace TestCom
{
[ComVisible(true)]
[Guid("6DC92920-8C3C-4C81-A615-BD0E3A332024")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ITestComObject
{
[DispId(1)]
string MyMethod(dynamic dictionary);
}
[ComVisible(true)]
[Guid("F52A463E-F03B-4703-860C-E86CDD6D04E3")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("TestCom.TestComObject")]
public class TestComObject : ITestComObject
{
string ITestComObject.MyMethod(dynamic dictionary)
{
StringBuilder sb = new StringBuilder();
if (dictionary != null)
{
foreach (object key in dictionary)
{
object p = dictionary[key];
if (p != null)
{
sb.AppendFormat("{0}={1}{2}", key, p, Environment.NewLine);
}
}
}
return sb.ToString();
}
}
}
Test ASP Page:
<%# Language=VBScript %>
<%
Dim testObj, params
Set testObj = Server.CreateObject("TestCom.TestComObject")
Set params = Server.CreateObject("Scripting.Dictionary")
params("lang") = "en-US"
params("num") = 42
Response.Write testObj.MyMethod(params)
Set testObj = Nothing
Set params = Nothing
%>
In normal case, the dynamic code would compile just once and subsequent calls would reuse it. However in our case it seems that the dynamic code is compiled on every single call. When i attach a memory profiler to IIS process i can clearly see additional objects from Microsoft.CSharp.RuntimeBinder.Semantics namespace appearing in gen2. This effectively causes a memory leak in our IIS process.
Any ideas how to fix this dynamic code compilation issue? Please note that rewriting all code to use PIA and COM interfaces is not always an option in our case.
I suggest you put any code which is susceptible to memory leak as a separate process - parent process communicate with such leaky processses via socket for instance. Then either freshly kick starts these leaky process on every call, or restarts them sometime during the evening!
Related
I am using excel-dna as base function, then I call a "vsto" function from an addin to trigger a web service request on the selected function. My issue is that I d like to use the DNA function to parse the ranges to be send to the service. It return a string currently ("waiting for service call..."), and if the VSTO methods call the function it passed another variable to return something else.
I cannot extract other thing than string, object comes back empty when I use "evaluate" in vsto.
I think the best way would be to reach a global cache variable stored in the vsto addin from the excel-dna function. I could not manage to to this.
Addins button push => addins evaluate Excel DNA => DNA store data in VSTO Addin variable => VSTO call the service and paste the returning data.
Thank you,
Ok I found out on:
MSN Blog
namespace AddIn{
[ComVisible(true)]
[Guid("****************************")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IAddinUtilities
{ void youraddinfunction();
}
[ClassInterface(ClassInterfaceType.None)]
public partial class ThisAddIn : IAddinUtilities
{
protected override object RequestComAddInAutomationService()
{ return this; }
public void yourfunction (){ DoSomething }
}
In the excel Dna function :
var application = (Application)XL.ExcelDnaUtil.Application;
var addin = application.COMAddIns.Item(AddinName);
var what = addin.Object;
what.youraddinfunction;
Yoyo's approach is strictly speaking correct, but for an approach that is more portable, I suggest combining ExcelDNA with NetOffice. Here is a snippet to get you started. Note that you will need to cleanup your Application references to COM proxy objects in the OnDisconnection method. For more details, check out Excel Addin Portability Tutorial
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
[ProgId("Sample.MyAddIn")]
public class MyRibbon : ExcelRibbon
{
public override void OnConnection(object comApp, ext_ConnectMode ConnectMode, object objAddin, ref Array custom)
{
// glue NetOffice + Excel DNA
m_ExcelApplication = new Application(null, m_ComApplication);
// other initialization...
}
}
I'm working with the revit api, and one of its problems is that it locks the .dll once the command's run. You have to exit revit before the command can be rebuilt, very time consuming.
After some research, I came across this post on GitHub, that streams the command .dll into memory, thus hiding it from Revit. Letting you rebuild the VS project as much as you like.
The AutoReload Class impliments the revit IExteneralCommand Class which is the link into the Revit Program.
But the AutoReload class hides the actual source DLL from revit. So revit can't lock the DLL and lets one rebuilt the source file.
Only problem is I cant figure out how to implement it, and have revit execute the command. I guess my C# general knowledge is still too limited.
I created an entry in the RevitAddin.addin manifest that points to the AutoReload Method command, but nothing happens.
I've tried to follow all the comments in the posted code, but nothing seems to work; and no luck finding a contact for the developer.
Found at: https://gist.github.com/6084730.git
using System;
namespace Mine
{
// helper class
public class PluginData
{
public DateTime _creation_time;
public Autodesk.Revit.UI.IExternalCommand _instance;
public PluginData(Autodesk.Revit.UI.IExternalCommand instance)
{
_instance = instance;
}
}
//
// Base class for auto-reloading external commands that reside in other dll's
// (that Revit never knows about, and therefore cannot lock)
//
public class AutoReload : Autodesk.Revit.UI.IExternalCommand
{
// keep a static dictionary of loaded modules (so the data persists between calls to Execute)
static System.Collections.Generic.Dictionary<string, PluginData> _dictionary;
String _path; // to the dll
String _class_full_name;
public AutoReload(String path, String class_full_name)
{
if (_dictionary == null)
{
_dictionary = new System.Collections.Generic.Dictionary<string, PluginData>();
}
if (!_dictionary.ContainsKey(class_full_name))
{
PluginData data = new PluginData(null);
_dictionary.Add(class_full_name, data);
}
_path = path;
_class_full_name = class_full_name;
}
public Autodesk.Revit.UI.Result Execute(
Autodesk.Revit.UI.ExternalCommandData commandData,
ref string message,
Autodesk.Revit.DB.ElementSet elements)
{
PluginData data = _dictionary[_class_full_name];
DateTime creation_time = new System.IO.FileInfo(_path).LastWriteTime;
if (creation_time.CompareTo(data._creation_time) > 0)
{
// dll file has been modified, or this is the first time we execute this command.
data._creation_time = creation_time;
byte[] assembly_bytes = System.IO.File.ReadAllBytes(_path);
System.Reflection.Assembly assembly = System.Reflection.Assembly.Load(assembly_bytes);
foreach (Type type in assembly.GetTypes())
{
if (type.IsClass && type.FullName == _class_full_name)
{
data._instance = Activator.CreateInstance(type) as Autodesk.Revit.UI.IExternalCommand;
break;
}
}
}
// now actually call the command
return data._instance.Execute(commandData, ref message, elements);
}
}
//
// Derive a class from AutoReload for every auto-reloadable command. Hardcode the path
// to the dll and the full name of the IExternalCommand class in the constructor of the base class.
//
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
public class AutoReloadExample : AutoReload
{
public AutoReloadExample()
: base("C:\\revit2014plugins\\ExampleCommand.dll", "Mine.ExampleCommand")
{
}
}
}
There is an easier approach: Add-in Manager
Go to Revit Developer Center and download the Revit SDK, unzip/install it, the check at \Revit 2016 SDK\Add-In Manager folder. With this tool you can load/reload DLLs without having to modify your code.
There is also some additional information at this blog post.
this is how you can use the above code:
Create a new VS class project; name it anything (eg. AutoLoad)
Copy&Paste the above code in-between the namespace region
reference revitapi.dll & revitapiui.dll
Scroll down to AutoReloadExample class and replace the path to point
your dll
Replace "Mine.ExampleCommand" with your plugins namespace.mainclass
Build the solution
Create an .addin manifest to point this new loader (eg.
AutoLoad.dll)
your .addin should include "FullClassName" AutoLoad.AutoReloadExample
This method uses reflection to create an instance of your plugin and prevent Revit to lock your dll file! You can add more of your commands just by adding new classes like AutoReloadExample and point them with seperate .addin files.
Cheers
I have a bit of a complex program which is giving me this apparently phantom error...
I'll start explaining with the help of this little example program I rigged that can throw my beautiful exception for anyone who runs it.
<!-- language: c# -->
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace so_redux {
static class Program {
[STAThread]
static void Main(){
CS2JS _class=new CS2JS();
}
}//class Program
class CS2JS{
public CS2JS(){
Func<String,Object> js_eval=initJS();
Object cs_ic=initCS();
string xc;
object res;
cs_ic.GetType().GetMethod("init").Invoke(cs_ic,null);
AppDomain.CurrentDomain.SetData("trespasser",cs_ic);
xc=#"function edata(fieldname:String,ival:String):Object{
var sob=System.AppDomain.CurrentDomain.GetData('trespasser');
var v1=sob.GetType().GetField(fieldname).GetValue(sob);
function HASH(s1:String,s2:String):Object{
var q1=sob.GetType().GetField(s1).GetValue(sob);
return q1.ITEM(s2);
}
var v2=v1.ITEM(ival);
return eval(v2);
}
edata('HT','foo');";
res=js_eval(xc);
// var xx;xx=new Hashtable();xx['sda']='1';eval(xx['sda']); OK
}
Func<String,Object> initJS(){
System.CodeDom.Compiler.CodeDomProvider jcc;
System.CodeDom.Compiler.CompilerParameters jcp;
System.CodeDom.Compiler.CompilerResults jcr;
System.Reflection.Assembly jas;
object jis;
string code;
Type t_ii;
code=#"#set #debug(off)
import System;
import System.Collections;
import System.Collections.Generic;
package internal_namespace{class internal_class{
public function internal_method(_code:String):Object{
return eval(_code);
}
}
}";
jcc=Microsoft.JScript.JScriptCodeProvider.CreateProvider("JScript");
jcp=new System.CodeDom.Compiler.CompilerParameters();
jcp.CompilerOptions="/fast-";
jcp.GenerateExecutable=false;
jcp.GenerateInMemory=true;
jcp.IncludeDebugInformation=false;
jcp.ReferencedAssemblies.Add("System.dll");
jcp.ReferencedAssemblies.Add("System.Core.dll");
jcp.WarningLevel=4;
jcr=jcc.CompileAssemblyFromSource(jcp,code);
jas=jcr.CompiledAssembly;
jis=jas.CreateInstance("internal_namespace.internal_class");
t_ii=jas.GetType("internal_namespace.internal_class");
return (s1)=>t_ii.InvokeMember("internal_method",System.Reflection.BindingFlags.InvokeMethod,null,jis,new object[]{s1});
}//initJS
Object initCS(){
var v1= Microsoft.CSharp.CSharpCodeProvider.CreateProvider("CSharp");
System.CodeDom.Compiler.CompilerParameters v2=new System.CodeDom.Compiler.CompilerParameters();
v2.GenerateExecutable=false;
v2.GenerateInMemory=true;
v2.IncludeDebugInformation=false;
v2.WarningLevel=4;
v2.ReferencedAssemblies.Add("System.dll");
v2.ReferencedAssemblies.Add("System.Core.dll");
string _code="public Hashtable2 HT;"+
"public void init(){"+
"HT=new Hashtable2();"+
"HT[\"foo\"]=\"1\";"+
"HT[\"bar\"]=\"HASH('HT','foo')\";"+
"}";
var v3="using System;using System.Collections;using System.Collections.Generic;"+
"namespace internal_namespace{public class Hashtable2:Hashtable{"+
"public Hashtable2():base(){} public Hashtable2(int N):base(N){}"+
"public Object ITEM(Object K){return this[K];} }"+
"[Serializable]public class internal_class{"+
"public internal_class(){}"+
_code+
"\n}}";
var v4=v1.CompileAssemblyFromSource(v2,v3);
var v5=v4.CompiledAssembly;
var v6=v5.GetType("internal_namespace.internal_class");
var v7=v5.CreateInstance("internal_namespace.internal_class");
return v7;
}//initCS
}//class CS2JS
}//namespace so_redux
The exception that is thrown is "index out of bounds", and it's thrown from JScript. The problem? It's that there is no array!
What this code is doing: first a JScript interpreter is initialized by compiling at runtime a class that "exports" an eval (one could do a dll, but in this case I didn't).
Then a C# assembly is compiled, an assembly that "exports" some user code (the variable _code in initCS is originally loaded by reading a text file).
After the initialization of the newly compiled class (the invoking of init()), I need the two assemblies (JScript and C#) to interact, so I need to pass data between them, and I thought of using AppDomain.
Note: in the C# assembly an Hashtable2 is defined because I put in there an ITEM method that one can use in alternative to the common property this[]: in this way debugging is easier (for examply by showing a holy MessageBox when accessing the values).
So, I pass the class instantiated in initCS to JScript, and JScript reads the internal Hashtable (HT). What I need to do is evaluate the data in the Hashtable, because it is supposed to be able to alter itself dynamically.
Everything works fine if I eval a string not taken from the Hashtable -- in the moment I take whatever is in the Hashtable and pass it to eval, then exceptions happen. Attention: the strings are absolutely the same (even comparing them with Equals) and they work, the difference is only from where they come from.
When the JScript function edata evals a string taken from the Hashtable, JScript says "index out of bounds", but as I was saying: I don't see any array there... (and maybe the problem is exactly that, dunno).
I admit I have my limitations in JScript, so if anybody could lend a hand to help understand WTF is going on, I would be really happy.
Temporary solution/workaround splitting the JScript function:
xc=#"function odata(fieldname:String,ival:String):Object{
var sob=System.AppDomain.CurrentDomain.GetData('trespasser');
var v1=sob.GetType().GetField(fieldname).GetValue(sob);
return v1.ITEM(ival);
}
odata('HT','bar');";
res=js_eval(xc);
xc=#"function HASH(s1:String,s2:String):Object{
var sob=System.AppDomain.CurrentDomain.GetData('trespasser');
var q1=sob.GetType().GetField(s1).GetValue(sob);
return q1.ITEM(s2);
}
eval("+res.ToString()+");";
res=js_eval(xc);
but if anybody really got any idea of why is wrong in the first example, please explain me!
I have been trying to follow this example (download the source code from a link on the site or here, but I keep running into an error that seems embedded in the example.
My procedure has been as follows (after installing the AppFabric SDK and other dependencies):
Download the source
Create a Service Namespace on the AppFabric.
Import the project into a new Windows Azure project with one Worker Role, make sure that it all compiles and that the default Worker Role Run() method starts and functions.
Configure the method GetInterRoleCommunicationEndpoint in InterRoleCommunicationExtension.cs with the ServiceNameSpace and IssuerSecret from my AppFabric Service Namespace (IssuerName and ServicePath stay default). This is a hard-wiring of my own parameters.
Copy/paste the initialization logic from the "SampleWorkerRole.cs" file in the demo into the OnStart() method of my project's Worker Role
Comment-out references to Tracemanager.* as the demo code does not have the Tracemanager methods implemented and they're not crucial for this test to work. There are about 7-10 of these references (just do a Find -> "Tracemanager" in entire solution).
Build successfully.
Run on local Compute Emulator.
When I run this test, during the initialization of a new InterRoleCommunicationExtension (the first piece of the inter-role communication infrastructure to be initialized, this.interRoleCommunicator = new InterRoleCommunicationExtension();), an error is raised: "Value cannot be null. Parameter name: contractType."
Drilling into this a bit, I follow the execution down to the following method in ServiceBusHostFactory.cs (one of the files from the sample):public static Type GetServiceContract(Type serviceType)
{
Guard.ArgumentNotNull(serviceType, "serviceType");
Type[] serviceInterfaces = serviceType.GetInterfaces();
if (serviceInterfaces != null && serviceInterfaces.Length > 0)
{
foreach (Type serviceInterface in serviceInterfaces)
{
ServiceContractAttribute serviceContractAttr = FrameworkUtility.GetDeclarativeAttribute<ServiceContractAttribute>(serviceInterface);
if (serviceContractAttr != null)
{
return serviceInterface;
}
}
}
return null;
}
The serviceType parameter's Name property is "IInterRoleCommunicationServiceContract," which is one of the classes of the demo, and which extends IObservable. The call to serviceType.GetInterfaces() returns the "System.IObservable`1" interface, which is then passed into FrameworkUtility.GetDeclarativeAttribute(serviceInterface);, which has the following code:
public static IList GetDeclarativeAttributes(Type type) where T : class
{
Guard.ArgumentNotNull(type, "type");
object[] customAttributes = type.GetCustomAttributes(typeof(T), true);
IList<T> attributes = new List<T>();
if (customAttributes != null && customAttributes.Length > 0)
{
foreach (object customAttr in customAttributes)
{
if (customAttr.GetType() == typeof(T))
{
attributes.Add(customAttr as T);
}
}
}
else
{
Type[] interfaces = type.GetInterfaces();
if (interfaces != null && interfaces.Length > 0)
{
foreach (object[] customAttrs in interfaces.Select(iface => iface.GetCustomAttributes(typeof(T), false)))
{
if (customAttrs != null && customAttrs.Length > 0)
{
foreach (object customAttr in customAttrs)
{
attributes.Add(customAttr as T);
}
}
}
}
}
return attributes;
}</code><br>
It is here that the issue arises. After not finding any customAttributes on the "IObservable1" type, it calls type.GetInterfaces(), expecting a return. Even though type is "System.IObservable1," this method returns an empty array, which causes the function to return null and the exception with the above message to be raised.
I am extremely interested in getting this scenario working, as I think the Publish/Subscribe messaging paradigm is the perfect solution for my application. Has anyone been able to get this demo code (from the AppFabric CAT Team itself!) working, or can spot my error? Thank you for your help.
Answered in the original blog post (see link below). Please advise if you are still experiencing problems. We are committed to supporting our samples on best effort basis.
http://blogs.msdn.com/b/appfabriccat/archive/2010/09/30/implementing-reliable-inter-role-communication-using-windows-azure-appfabric-service-bus-observer-pattern-amp-parallel-linq.aspx#comments
I am getting a memory leak whenver a new RPC thread in a DCOM server (c++ DCOM server) invokes the following managed C++ method
void CToolDataClient::SetLotManagerActive(bool bLotManagerActive)
{
if( m_toolDataManager != nullptr)
{
m_toolDataManager->LotActive = bLotManagerActive;
}
}
I get the managed C++ object pointer using the floowing code
typedef bool (*FPTR_CREATEINTERFACE)(CToolDataInterface ** ppInterface);
FPTR_CREATEINTERFACE fnptr = (FPTR_CREATEINTERFACE)GetProcAddress(hModule,(LPTSTR)"CreateInstance");
if ( NULL != fnptr )
{
CICELogger::Instance()->LogMessage("CToolDataManager::CToolDataManager", Information,
"Created instance of DataManagerBridge");
fnptr(&m_pToolDataInterface);
}
This is how I invoke the managed call in the DCOME server C++ portion
void CToolDataManager::SetLotManagerActive(bool bLotManagerActive)
{
if(m_pToolDataInterface != NULL)
{
m_pToolDataInterface->SetLotManagerActive(bLotManagerActive);
}
}
The callstack given below indicate the location of the memory leak . Is there any ways to solve this memory leak? Please help me
ntdll!RtlDebugAllocateHeap+000000E1
ntdll!RtlAllocateHeapSlowly+00000044
ntdll!RtlAllocateHeap+00000E64
mscorwks!EEHeapAlloc+00000142
mscorwks!EEHeapAllocInProcessHeap+00000052
**mscorwks!operator new[]+00000025
mscorwks!SetupThread+00000238
mscorwks!IJWNOADThunk::FindThunkTarget+00000019
mscorwks!IJWNOADThunkJumpTargetHelper+0000000B
mscorwks!IJWNOADThunkJumpTarget+00000048
ICEScheduler!CToolDataManager::SetLotManagerActive+00000025** (e:\projects\ice\ice_dev\trunk\source\application source\iceschedulersystem\icescheduler\tooldatamanager.cpp, 250)
ICEScheduler!SetLotManagerActive+00000014 (e:\projects\ice\ice_dev\trunk\source\application source\iceschedulersystem\icescheduler\schddllapi.cpp, 589)
ICELotControl!CLotDetailsHandler::SetLotManagerStatus+0000006C (e:\projects\ice\ice_dev\source\application source\icelotsystem\icelotcontrol\lotdetailshandler.cpp, 1823)
ICELotControl!CLotManager::StartJob+00000266 (e:\projects\ice\ice_dev\source\application source\icelotsystem\icelotcontrol\lotmanager.cpp, 205)
RPCRT4!Invoke+00000030
RPCRT4!NdrStubCall2+00000297
RPCRT4!CStdStubBuffer_Invoke+0000003F
OLEAUT32!CUnivStubWrapper::Invoke+000000C5
ole32!SyncStubInvoke+00000033
ole32!StubInvoke+000000A7
ole32!CCtxComChnl::ContextInvoke+000000E3
ole32!MTAInvoke+0000001A
ole32!AppInvoke+0000009C
ole32!ComInvokeWithLockAndIPID+000002E0
ole32!ThreadInvoke+000001CD
RPCRT4!DispatchToStubInC+00000038
RPCRT4!RPC_INTERFACE::DispatchToStubWorker+00000113
RPCRT4!RPC_INTERFACE::DispatchToStub+00000084
RPCRT4!RPC_INTERFACE::DispatchToStubWithObject+000000C0
RPCRT4!LRPC_SCALL::DealWithRequestMessage+000002CD
RPCRT4!LRPC_ADDRESS::DealWithLRPCRequest+0000016D
RPCRT4!LRPC_ADDRESS::ReceiveLotsaCalls+0000028F
First, is LotActive a member variable/field (pure data) or a property?
I think that it is a property, and before it can be set, the JIT has to compile the code for the setter. In desktop .NET, native code produced by the JIT compilation process is not garbage collected, instead it exists for the lifetime of the AppDomain, so it could look like a leak.
Can you check whether each call to this function leaks another object, or the leak just occurs once?