data contract is already present and the contracts are not equivalent - c#

I have an interface contract, and I'm developing a WCF with this contract.
But, there is something wrong because I'm getting this error:
The DataContract element of type ' Contract. Xyt. ObjectWithValXyt'1
[[Contract.Xyt.LayoutXyt, Contract, Version = 2. 5. 0. 0, Culture = neutral, PublicKeyToken = null]]'
You can add to DataContractSet, since the type ' Contract. Xyt. ObjectWithValXyt'1
[[Contract.Xyt.UnitTypeXyt, Contract, Version = 2. 5. 0. 0, Culture = neutral, PublicKeyToken = null]]'
with the same data contract 'ObjectWithVal' in the namespace 'http://myhost.com/Service/2013/09' is already present and the contracts are not equivalent.
And this is a piece of the implementation:
public class Service2 : IAutomationServiceWs
{
public List<Contract.Xyt.UnitTypeInfoXyt> GetUnitTypeInfos()
{
return null;
}
public Contract.Xyt.ObjectWithValXyt<Contract.Xyt.UnitTypeXyt> GetUnitTypeAndValidate(Contract.Xyt.UnitTypeRefXyt unitTypeRef)
{
return null;
}
public List<Contract.Xyt.LayoutInfoXyt> GetLayoutInfos()
{
return null;
}
Why am I getting this error when I run this service on Internet Explorer?

As far as I can tell from the error message, you have 2 different contracts with the same name (ObjectWithVal). You might try to merge them or change the name of one of them.

Try to do a 'Clean' before a 'Build' or debug.

Related

Strategy for creating C# library for Third party integration with multiple wsdl versions

We need to integrate third party SOAP api with our system. As we are SaaS solution provider, we need to support all version of third party.
We have configuration that Customer A has version 1.8, Customer B has version 2.0. (Version may took months for new version.)
What I am looking for is a general strategy for creating a library that can work with all versions.
As a solution I think to create multiple namespace version wise in single C# library.
TP1.DLL
Namespace - TP1_v1.8
Entity1 (Proxy class)
Entity2 (Proxy class)
Namespace - TP2_v2.0
Entity1 (Proxy class)
Entity2 (Proxy class)
I want wrapper class for all entity irrespective of version. so i will call that wrapper class and it will initialize object with required version.
How can i do that ? Is it right way to handle a situation like this?
If any further information is needed, let me know!
Thanks!
Ankur Kalavadia
you can use following solution for your problem which help to you in your implementation.
--> First you create common interface which can be usefull for common identifier of all the same types
--> Make Seperate NameSpace by version name
DefaultNameSpace : ABC.XYZ
Version : 1.6.2
Then make the namespace patterns as
e.g. ABC.XYZ.V162 (Replcing . and set prefix as per classname norms (always start with Alphabet ) )
Create Class under above namespace with implementing interface
--> Create same classname for all the versions ( e.g. class1 , class2 common in version v1, v2 with diferent implementation )
--> Create below common function to generate relevant object
public static iTestInterface GetEntity(string className)
{
string versionPrefix = "v_";
string strVersion = 1.6.2;
string dllPath =System.Web.HttpRuntime.BinDirectory;
string dllName = "dllName.dll";
string Version = versionPrefix +
string strclassNameWithFullPath = dllPath + Version.Replace(".", "") + "." + className;
try
{
string strAssemblyWithPath = string.Concat(dllPath, dllName);
if (!System.IO.File.Exists(strAssemblyWithPath))
{
return null;
}
System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFile(strAssemblyWithPath);
Type t = assembly.GetType(strclassNameWithFullPath);
object obj = Activator.CreateInstance(t);
return (iTestInterface)obj;
}
catch (Exception exc)
{
//string errStr = string.Format("Error occured while late assembly binding. dllPath = {0}, dllName = {1}, className = {2}.", dllPath, dllName, className);
return null;
}
}
--> Call function as below
iTestInterface obj = GetEntity(classnameString);
--> call relevent object methods. Above call will be common for all relevant classes.
Thanks & Regards
Shailesh Chopra

Is it posible to perform QueryInterface on behalf of VBScript

I'm trying to create a COM class with one method that will cast an object to a specific interface on behalf of VBScript.
This is the method signature I'm using:
public object GetInterface(object unknown, string iid)
I thought this would be possible because if the method explicitly declares the return type as :
public IRequestedInterface GetInterface(object unknown, string iid)
Then VBScript gets the reference to the desired interface.
So I tried just casting to the interface
return (IRequestedInterface)unknown;
Unfortunately, VBScript gets a reference to the default interface instead of the requested interface.
I have tried getting round this by creating a custom marshaller using ICustomMarshaler.
I thought this would work because the method MarshalManagedToNative returns a IntPtr.
Because of this I thought that if i just returned the IntPtr to the interface
return Marshal.GetComInterfaceForObject(unknown, typeof(IRequestedInterface));
it would work. But, obviously, it didn't have the desired effect :(
So does anybody know if it is posible and how you would do it?
EDIT:
I thought it would be helpful to add a concrete example (although it is contrived) to explain why I haven't accepted that VBScript will always get the default interface. I'm still clinging to my hope.
Below you will find the contents of 3 files, 'TestLib.cs', 'Build.cmd' and 'Test.vbs'. These hopefully demonstrate why I still think it 'should' be possible.
Note: I have tested this on Windows XP SP3 (x86).
TestLib.cs
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
[assembly: ComVisible(false)]
[assembly: Guid("64e20009-c664-4883-a6e5-1e36a31a0fd8")]
[assembly: AssemblyVersion("2012.06.*")]
[ComVisible(true)]
[Guid("EB77C7B1-D1B9-4BB3-9D63-FBFBD56C9ABA")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IPerformQi
{
[DispId(1000)]
object GetInterface(object unknown, string iid);
[DispId(2000)]
IRequested GetIRequested(object unknown);
}
[ComVisible(true)]
[Guid("7742BC0A-8719-483E-B1DF-AE9CD9A958DC")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IDefault
{
[DispId(1000)]
void SayHello(string name);
}
[ComVisible(true)]
[Guid("FFF34296-2A06-47D4-B09C-B93B63D5CC53")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IRequested
{
[DispId(1000)]
void SayGoodbye(string name);
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(IPerformQi))]
[Guid("222BB88D-B9FA-4F23-8DB3-BA998F4E668B")]
[ProgId("TestLib.PerformQi")]
public class PerformQi : IPerformQi
{
object IPerformQi.GetInterface(object unknown, string iid)
{
if(iid == "FFF34296-2A06-47D4-B09C-B93B63D5CC53")
return (IRequested)unknown;
throw new Exception("Unable to find inteface");
}
IRequested IPerformQi.GetIRequested(object unknown)
{
return (IRequested)unknown;
}
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(IDefault))]
[Guid("174ABED6-3325-4878-89E3-BF8BD1107488")]
[ProgId("TestLib.Test")]
public class Test : IDefault, IRequested
{
void IDefault.SayHello(string name)
{
MessageBox.Show(string.Format("Hello '{0}'", name));
}
void IRequested.SayGoodbye(string name)
{
MessageBox.Show(string.Format("Goodbye '{0}'", name));
}
}
Build.cmd
"%windir%\Microsoft.Net\Framework\v4.0.30319\csc.exe" /out:TestLib.dll /target:library /r:System.Windows.Forms.dll TestLib.cs
"%windir%\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" TestLib.dll /codebase /tlb:TestLib.tlb
PAUSE
Test.vbs
Dim oPerformQi 'As TestLib.PerformQi
Dim oTest 'As TestLib.Test
Dim oTest2 'As IRequested
Dim oTest3 'As IRequested
Set oPerformQi = CreateObject("TestLib.PerformQi")
Set oTest = CreateObject("TestLib.Test")
Call oTest.SayHello("Robert")
Set oTest2 = oPerformQi.GetIRequested(oTest)
'Note: This works
Call oTest2.SayGoodbye("Robert")
Set oTest3 = oPerformQi.GetInterface(oTest, "FFF34296-2A06-47D4-B09C-B93B63D5CC53")
'Note: This does not work
Call oTest3.SayGoodbye("Robert")
Using the call oPerformQi.GetIRequested(oTest) makes the call to oTest3.SayGoodbye("Robert") work. This makes me think you are not limited to just the default interface in VBS.
Perhaps .Net is not capable of returning the specified interface because of an implicit cast on the return value? Ideally I would use generics for this, but as we all know COM does not support genrics.
Under this restriction is there any other way that you can think of to achieve this?
EDIT 2:
I have found that I can achieve this using VB6, below is the code for the class.
Option Explicit
Public Function GetInterface(ByVal oUnknown As Object, ByVal IID As String) As Variant
Dim oIRequested As IRequested
If IID = "FFF34296-2A06-47D4-B09C-B93B63D5CC53" Then
Set oIRequested = oUnknown
Set GetInterface = oIRequested
Else
Err.Raise 1, , "Unable to find inteface"
End If
End Function
I would still like to find a C# version if anybody can shed some light on the subject i would appreciate it.
In order to have multiple IDispatch-derived interfaces implemented on a single object, to be accessible from scripting environment you should rather implement IDispatchEx and have its methods called once a call from script is taking place.
The problem you are facing is caused by the fact that script queries for your IDispatch first, and both your IDispatch-derived interfaces return the same "main" IDispatch leaving no chance for methods of other interfaces to be accessible.
When VBS host is about to call a method on your object, it first queries IDispatchEx. If found, the calls are delivered via IDispatchEx::InvokeEx and your COM Class can internally route the call to the proper IDispatch implementation, both private or forward to external/inner object.
In case IDispatchEx is not found, it looks for IDispatch and there you are in trouble because it sees only your "main" interface. That is, the workaround for you is to implement IDispatchEx. You can do it either way: implement right on your COM class, or instead create a proxy class to accept scripting calls via IDispatchEx::InvokeEx and forward to correct IDispatch in your code.
Example: Both A and B classes implement IX and IY interfaces, B additionally implements IDispatchEx. Interface methods are IX::X1, IY::Y1.
On Error Resume Next
Set A = CreateObject("Test.A")
WScript.Echo A.X1 ' Success, via IX::Invoke
WScript.Echo A.Y1 ' Failure, A's IDispatch is IX's parent and does not have Y1 method
Set B = CreateObject("Test.B")
WScript.Echo B.X1 ' Success, via IDispatchEx::InvokeEx
WScript.Echo B.Y1 ' Success, via IDispatchEx::InvokeEx

Type.GetType() returning null [duplicate]

This question already has answers here:
Type.GetType("namespace.a.b.ClassName") returns null
(17 answers)
Closed 7 years ago.
I have a web application that dynamically creates a web page using usercontrols.
Within my code I have the following:
private void Render_Modules()
{
foreach (OnlineSystemPageCustom.OnlineSystemPageHdr.OnlineSystemPageModule item in custompage.Header.Modules)
{
if (item.ModuleCustomOrder != 99 && !item.ModuleOptional)
{
string typeName = item.ModuleInternetFile;
Type child = Type.GetType(typeName);
webonlinecustombase ctl = (webonlinecustombase)Page.LoadControl("../IPAM_Controls/webtemplatecontrols/" + child.Name.ToString() + ".ascx");
ctl.Event = Event;
ctl.custompage = custompage;
ctl.custommodule = item;
this.eventprogrammodules.Controls.Add(ctl);
}
}
}
The "typeName" that is being returned (example) is:
IPAMIntranet.IPAM_Controls.webtemplatecontrols.eventorgcommittee
The namespace for the user controls is as follows:
namespace IPAMIntranet.IPAM_Controls
The problem I am having is that Type.GetType(typeName) is returning null. What am I missing here?
Type.GetType(string) only looks in the currently executing assembly and mscorlib when you don't specify the assembly name within the string.
Options:
Use the assembly-qualified name instead
Call Assembly.GetType(name) on the appropriate assembly instead
If you have an easy way of getting hold of the relevant assembly (e.g. via typeof(SomeKnownType).Assembly) then the second option is probably simpler.
Type.GetType looks as the calling assembly, and a few system assemblies. For anything else, you must either use assemblyInstance.GetType(typeName), or you must use the "assembly qualified name" of the type, which includes the assembly details in which the type can be found. Otherwise, it wont be found, and will return null. You can get that from:
string aqn = someType.AssemblyQualifiedName;
I had a very similar problem to the original poster, except that I needed to instantiate the code-behind class of my custom user-control in a static utility class rather than an ASPX page, so LoadControl wasn't available to me. Here's what I ended up doing:
public static class Utils
{
public static string MyFunc(string controlClassName)
{
string result = "";
// get a list of all assemblies in this application domain
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
// the trouble is that we don't know which assembly the class is defined in,
// because we are using the "Web Site" model in Visual Studio that compiles
// them on the fly into assemblies with random names
// -> however, we do know that the assembly will be named App_Web_*
// (http://msdn.microsoft.com/en-us/magazine/cc163496.aspx)
foreach (Assembly assembly in assemblies)
{
if (assembly.FullName.StartsWith("App_Web_"))
{
// I have specified the ClassName attribute of the <%# Control %>
// directive in the relevant ASCX files, so this should work
Type t = assembly.GetType("ASP." + controlClassName);
if (t != null)
{
// use reflection to create the instance (as a general object)
object o = Activator.CreateInstance(t);
// cast to the common base type that has the property we need
CommonBaseType ctrl = o as CommonBaseType;
if (ctrl != null)
{
foreach (string key in ctrl.PropertyWeNeed)
{
// finally, do the actual work
result = "something good";
}
}
}
}
}
return result;
}
}
It's not pretty and not very efficient, and is liable to break if the App_Web_* naming convention changes (although you could then just look through all of them): but it does work ...

T4 templates - refreshing solution explorer in Visual Studio 2010 from one application domain to another

<## template debug="true" hostspecific="true" language="C#" #>
<## assembly name="EnvDTE80" #>
<## include file="T4Toolbox.tt" #>
<#
IServiceProvider serviceProvider = (IServiceProvider)this.Host;
EnvDTE80.DTE2 dte = (EnvDTE80.DTE2)serviceProvider.GetService(typeof(EnvDTE.DTE));
//add a file to a project and add its dependupon build property.
//I want to refresh teh solution explorer window to show the hierarchy between 2 files
//You will see this kind of relationship between Forms.cs and Form1.Designer.cs files.
EnvDTE.UIHierarchy solExplorer = dte.ToolWindows.SolutionExplorer;
solExplorer.Parent.Activate();
dte.ExecuteCommand("View.Refresh", string.Empty);
I am trying to refresh the solution explorer's tool window so I can see the newly created files nested. I know that T4 templates are executed in one application domain and calls are made into Visual Studio Appdomain using remoting. I am getting this error about serialization.
So is there a way I can refresh solution explorer tool window (solExplorer.Parent) by first activating it (I was told).
Type 'Microsoft.VisualStudio.Platform.WindowManagement.DTE.WindowBase' in Assembly 'Microsoft.VisualStudio.Platform.WindowManagement, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' is not marked as serializable.
Update: Based on Gereth's comment.
Thanks, Gereth I tried this, but it returns COMException,
I don't have an error about Serialization of Microsoft.VisualStudio.Platform.WindowManagement.DTE.WindowBase class and Activate method seems to have succeded. The error is now on dte.ExecuteCommand method.
//object dteObject = GetCOMService(serviceProvider, typeof(EnvDTE80.DTE2));
object dteObject1 = GetCOMService(serviceProvider, typeof(EnvDTE.DTE));
EnvDTE80.DTE2 dte = (EnvDTE80.DTE2)dteObject1;
COMException raised when executing this line:
dte.ExecuteCommand("View.Refresh", string.Empty);
Message "Error HRESULT E_FAIL has been returned from a call to a COM component."
Source "EnvDTE80"
StackTrace "at EnvDTE80.DTE2.ExecuteCommand(String CommandName, String CommandArgs)
ErrorCode -2147467259
What to try next?
Thanks
Rad
There's a section of DTE commands that don't stay with COM marshaling once the CLR notices that both ends of the remoting pipe are written in managed code. However, given these components are not actually set up to be .Net remotable, but ARE set up to be COM remotable, this type of error occurs.
In general, if the COM marshaling on the particular DTE object in question is set up correctly, you should be able to use the following code to get moving again.
Call it instead of your vanilla service call to get the DTE.
public static Object GetCOMService(IServiceProvider provider, Type type)
{
Object ret;
ret = provider.GetService(type);
if (ret == null)
{
return ret;
}
try
{
return Marshal.GetObjectForIUnknown(Marshal.GetIUnknownForObject(ret));
}
catch (Exception)
{
return ret;
}
}
I finally got this to work by unloading and reloading the project. The project has to be selected in the Solution Explorer otherwise you'll get a COMException.
IServiceProvider hostServiceProvider = (IServiceProvider)Host;
// see #GarethJ's answer for the following
DTE2 dte2 = GetCOMService(hostServiceProvider, typeof(EnvDTE.DTE)) as DTE2;
object dteObject1 = GetCOMService(hostServiceProvider, typeof(EnvDTE.DTE));
EnvDTE80.DTE2 dte2 = (EnvDTE80.DTE2)dteObject1;
var solExplorer = dte2.ToolWindows.SolutionExplorer;
solExplorer.Parent.Activate();
ProjectItem containingProjectItem = dte2.Solution.FindProjectItem(templateFile);
Project project = containingProjectItem.ContainingProject;
UIHierarchy solExplorerHierarchy = solExplorer.Parent.Object as UIHierarchy;
string projectSolutionPath = Path.Combine(dte2.Solution.Properties.Item("Name").Value.ToString(), project.Name);
var projectItem = solExplorerHierarchy.GetItem(projectSolutionPath);
projectItem.Select(vsUISelectionType.vsUISelectionTypeSelect);
dte2.ExecuteCommand("Project.UnloadProject", "");
dte2.ExecuteCommand("Project.ReloadProject", "");
And then any newly created nested items appear. I'm using VS2012 and T4Toolbox 11.7.
Thank you Gareth. Your solution works very well.
I have extended my "GetService" method:
private T GetService<T>(Type type) where T : class
{
IServiceProvider hostServiceProvider = (IServiceProvider)Host;
if (hostServiceProvider == null)
{
throw new Exception("Host property returned unexpected value (null)");
}
object serviceObj = hostServiceProvider.GetService(type);
try
{
serviceObj = Marshal.GetObjectForIUnknown(Marshal.GetIUnknownForObject(serviceObj));
}
catch (Exception) { }
T service = serviceObj as T;
if (service == null)
{
throw new Exception("Unable to retrieve service");
}
return service;
}

Get CLSID by PIA interface Type

Edit: Looks like Jon Skeet had some similar questions: How does the C# compiler detect COM types?
How can I get the CLSID for a given interface within a Primary Interop Assembly? Here's what I'm talking about:
// The c# compiler does some interesting magic.
// The following code ...
var app = new Microsoft.Office.Interop.Outlook.Application();
// ... is compiled like so (disassembled with Reflector):
var app =((Microsoft.Office.Interop.Outlook.Application)
Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("0006F03A-0000-0000-C000-000000000046"))));
Microsoft.Office.Interop.Outlook.Application is an interface, and therefore it cannot be instantiated directly. What's interesting here is that c# lets you treat these COM interfaces as if they were classes that you can instantiate with the new keyword.
What I want to know is, given the System.Type for a given interface, how can I get the CLSID?
Note: I ultimately want to be able to create an instance given the interface's System.Type - I don't really care how. I'm assuming here that the easiest way to do this would be to get CLSID given the Type, just as the c# compiler does.
Here's my current solution:
// Get the PIA assemby name, using the GUID of the typlib
string asmName;
string asmCodeBase;
var conv = new System.Runtime.InteropServices.TypeLibConverter();
conv.GetPrimaryInteropAssembly(new Guid("00062FFF-0000-0000-C000-000000000046"), 9, 3, 0, out asmName, out asmCodeBase);
// Load the PIA, and get the interface type
var assembly = System.Reflection.Assembly.Load(asmName);
var type = assembly.GetType("Microsoft.Office.Interop.Outlook.Application");
// Get the coclass
var coClassAttr = (System.Runtime.InteropServices.CoClassAttribute)
type.GetCustomAttributes(typeof(System.Runtime.InteropServices.CoClassAttribute), false)[0];
var coClass = coClassAttr.CoClass;
// Instantiate the coclass
var app = Activator.CreateInstance(coClassAttr.CoClass);
// If needed, the CLSID is also available:
var clsid = coClass.GUID;
I figured this out by disassembling the GAC'd PIA. I noticed that Outlook.Application was decorated with a CoClassAttribute, like so:
[ComImport, Guid("00063001-0000-0000-C000-000000000046"), CoClass(typeof(ApplicationClass))]
public interface Application : _Application, ApplicationEvents_11_Event
{
}
ApplicationClass looks something like:
[ComImport, ClassInterface((short) 0), ComSourceInterfaces("Microsoft.Office.Interop.Outlook.ApplicationEvents_11\0Microsoft.Office.Interop.Outlook.ApplicationEvents\0Microsoft.Office.Interop.Outlook.ApplicationEvents_10\0"), Guid("0006F03A-0000-0000-C000-000000000046"), TypeLibType((short) 11)]
public class ApplicationClass : _Application, Application, ApplicationEvents_11_Event, ApplicationEvents_Event, ApplicationEvents_10_Event
{
//...
}
Let me know what you all think, so I can decide if I should mark this as the chosen answer.
Try the GUID property.

Categories

Resources