Consuming a .NET WebService using a C++ client - c#

I have a webservice that queries a DB and returns the results of those queries.
However the webservice does not have direct access to the DB, instead, it queries it using a user created library, with specific methods for retrieving Users, names, etc.
I've included the library in the webservice project by selecting add > reference and I get no compiling errors or warnings on my webservice code.
I have created the client libraries using svcutil.exe and wsutil.exe and everything went OK, without warnings.
On my client code I get a "There was an error processing tempuri.org.xsd","Error generating code for DataSet ''.", and "Unable to convert input xml file to DataSet. The nested table 'Utilizador' which inherits the respective namespace cannot have multiple tables in different namespaces".
The last error was translated to Portuguese, and I did my best to translate it back to English, so YMMV... 'Utilizador' is a table name on my DB and a class name on the library that accesses the DB.
I'm using this code to consume the WebService:
#include "stdafx.h"
#include "WebServices.h"
#include "schemas.microsoft.com.2003.10.Serialization.xsd.h"
#include "tempuri.org.xsd.h"
#include "tempuri.org.wsdl.h"
#include <string>
#include <iostream>
#include <stdlib.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
unsigned int *listSize;
Utilizador **arrayUser;
HRESULT hr = ERROR_SUCCESS;
WS_ERROR* error = NULL;
WS_HEAP* heap = NULL;
WS_SERVICE_PROXY* proxy = NULL;
WS_ENDPOINT_ADDRESS address = {};
WS_STRING url= WS_STRING_VALUE(L"http://localhost:51765/Graph4Social.svc");
address.url = url;
hr = WsCreateHeap(2048, 512, NULL, 0, &heap, error);
WS_HTTP_BINDING_TEMPLATE templ = {};
//criação do proxy para o serviço
//hr = BasicHttpBinding_IGraph4WebService_CreateServiceProxy(&templ, NULL, 0, &proxy, error);
//WsCreateServiceProxy(&templ, NULL, 0, &proxy, error);
hr = BasicHttpBinding_IGraph4Social_CreateServiceProxy(&templ, NULL, 0, &proxy, error);
hr = WsCreateServiceProxy(WS_CHANNEL_TYPE_REQUEST,WS_HTTP_CHANNEL_BINDING,NULL,NULL,0,NULL,0,&proxy,error);
hr = WsOpenServiceProxy(proxy,&address,NULL,error);
hr = BasicHttpBinding_IGraph4Social_getUserList(proxy,listSize,&arrayUser,heap, NULL,0, NULL,error);
for (unsigned int i = 0; i < *listSize; i++)
cout << "ID Utilizador: " + arrayUser[i]->idUtilizador;
return 0;
}
This is the WebService code for the Interface:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using TM_TDG.WithDataSets.BLL;
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IGraph4Social" in both code and config file together.
[ServiceContract]
public interface IGraph4Social
{
[OperationContract]
IList<Utilizador> getUserList();
}
And this is the code for the Class that implements the interface:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using TM_TDG.WithDataSets.BLL;
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Graph4Social" in code, svc and config file together.
public class Graph4Social : IGraph4Social
{
public IList<Utilizador> getUserList()
{
RedeSocial rede = RedeSocial.getRedeSocial();
IList<Utilizador> userList = rede.getUserList(true); //so queremos os utilizadores activos
return userList;
}
}
I have googled this error and can't seem to find an answer. I hope someone can help me with this, as I've been stuck for days on this issue!
Thanks!

I actually solved this last night by mere chance! It turns out I was placing all files generated by svcutil.exe and wsutil.exe on the project page(including the .xsd and .wsdl generated by svcutil.exe). I was also adding all items to the visual studio project, although, obviously, I was only including the .h files. I thought that the compiler was only going to look at the .h and the corresponding .c files, but it turns out, it was looking at the .xsd and .wsdl too. When I deleted those files, the compiler worked flawlessly!
So, PEBKAC...
Dunno if this is Visual Studio related or if this behaviour can be reproduced with gc++, for example.

Related

Where do I put the dlls for edge.js to access

I have been using edge.js to call a C# function from within my Node.js app, however when I go to execute the C# code I get for example:
Metadata file 'System.Collections.Generic.dll' could not be found
Metadata file 'System.Text.dll' could not be found
...
My code is this below, basically wanting to run a SSIS package using a stored procedure which I am calling from C#. Basically all my referenced dll's can't be found? Where should I put the dlls for edge to find them?
var executeSQL = edge.func(function() {
/*
#r "System.Data.dll"
#r "System.Collections.Generic.dll"
#r "System.Linq.dll"
#r "System.Text.dll"
using System.Linq;
using System.Text;
using System.Data;
using System.Collections.Generic;
using System.Threading.Tasks;
public class StartUp
{
public async Task<object> Invoke(object input)
{
string result = string.Empty;
string packagePath = #"\SSISDB\test\package.dtsx";
string spName = "storedProcName";
using (var conn = new System.Data.SqlClient.SqlConnection("connectionString"))
using (var command = new System.Data.SqlClient.SqlCommand(spName, conn)
{
CommandType = System.Data.CommandType.StoredProcedure
})
{
conn.Open();
command.Parameters.AddWithValue("#PackagePath", packagePath);
command.ExecuteNonQuery();
Console.WriteLine("Finished");
};
return null;
}
}
*/
});
I know I can do this without C# and just use a module within node like mssql to execute the stored procedure but this was just an example test to get used to using edge.js
The comment from stuartd was correct in the sense to put the dlls under the same directory as the script (which I had tried) but I was still having the same issue. I solved my problem by having my C# code as a separate file and then referenced that file as below as part of the executeSSIS function. payload is just the object that gets passed from my node.js script to my C# script. Doing it this way solved my issue.
var payload = {
filePath: 'C:/temp/xlsx/' + req.file.filename,
path: req.packageName,
server: req.server
};
var executeSSIS = edge.func({
source: __dirname + '/cs/Program.cs',
references: [
__dirname + '/cs/System.Data.dll'
]
});
executeSSIS(payload);

Native C++ program crashes on startup with C++/CLI & C# interop DLL

I'm in a situation where I need to wrap C# WPF UserControls in a C++/CLI wrapper to use in a native C++ program. The native program uses MFC heavily and is compiled in VS2010. I've properly generated the C++/CLI .lib and .dll files in a separate solution and linked to them from the MFC application, which compiles and links successfully, generating the executable as usual. However, when I go to launch the MFC application, I get an access violation error 0xc0000005 before it even gets to main(). When I comment out the wrapper code, the program launches normally.
To try and isolate the problem, I tried creating a completely separate native C++ project whose sole purpose is to call the wrapper class with dummy data. This project reaches main() but throws an exception (0xe0434352) when I call the constructor for the wrapper class.
I've tried searching for any possible solutions, but the one the most closely matches my situation says to check the function signatures to make sure I'm passing in the right number of arguments (I am). I've also looked up the 0xe0434352 exception from the standalone project and it appears to be a generic .NET exception.
I also saw this question posted, but was hoping the solution would be simpler than that. I've been following the instructions on this blog to create the wrapper class.
I'm including all code but the MFC application code, since it's not even loading to main(). I'm hoping that if I can manage to resolve the issue in the brand new project, the MFC application will start.
C# WPF:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ManagedWPFLink
{
public struct TestResultData
{
public string inspectionType;
public string testResult;
public string measuredValue;
public string passCondition;
public string comments;
}
/// <summary>
/// Interaction logic for TestResultsDialog.xaml
/// </summary>
public partial class TestResultsDialog : UserControl
{
private Window window;
public TestResultsDialog()
{
InitializeComponent();
DataGridTextColumn col1 = new DataGridTextColumn();
DataGridTextColumn col2 = new DataGridTextColumn();
DataGridTextColumn col3 = new DataGridTextColumn();
DataGridTextColumn col4 = new DataGridTextColumn();
DataGridTextColumn col5 = new DataGridTextColumn();
this.testResultsGrid.Columns.Add(col1);
this.testResultsGrid.Columns.Add(col2);
this.testResultsGrid.Columns.Add(col3);
this.testResultsGrid.Columns.Add(col4);
this.testResultsGrid.Columns.Add(col5);
col1.Binding = new Binding("inspectionType");
col2.Binding = new Binding("testResult");
col3.Binding = new Binding("measuredValue");
col4.Binding = new Binding("passCondition");
col5.Binding = new Binding("comments");
col1.Header = "Inspection Type";
col2.Header = "Test Result";
col3.Header = "Measured Value";
col4.Header = "Pass Condition";
col5.Header = "Comments";
this.window = new Window
{
Title = "Inspection Results",
Content = this,
SizeToContent = SizeToContent.WidthAndHeight,
ResizeMode = ResizeMode.NoResize
};
}
public void addRow(string inspectionType, string testResult, string measuredValue, string passCondition, string comments)
{
TestResultData data = new TestResultData();
data.inspectionType = inspectionType;
data.testResult = testResult;
data.measuredValue = measuredValue;
data.passCondition = passCondition;
data.comments = comments;
this.testResultsGrid.Items.Add(data);
}
public void deleteAllRows()
{
this.testResultsGrid.Items.Clear();
}
public void showDialog()
{
this.window.ShowDialog();
}
}
}
C# XAML:
<UserControl x:Class="ManagedWPFLink.TestResultsDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="600">
<Grid>
<DataGrid AutoGenerateColumns="True" Height="376" HorizontalAlignment="Left" Margin="12,12,0,0" Name="testResultsGrid" VerticalAlignment="Top" Width="576" ItemsSource="{Binding}" MinColumnWidth="40">
</DataGrid>
</Grid>
</UserControl>
C++/CLI header:
// ManagedWPFLink.h
#pragma once
namespace WPFLink
{
class WPFPrivate;
class __declspec(dllexport) WPFWrapper
{
private:
WPFPrivate *internalWrapper;
public:
WPFWrapper();
~WPFWrapper();
void addItems(const char **data);
void deleteAllRows();
void showDialog();
};
}
C++/CLI source:
// This is the main DLL file.
#include "stdafx.h"
#using <WindowsBase.dll>
#using <PresentationCore.dll>
#using <PresentationFramework.dll>
#using "ManagedWPFLink.dll"
#include "WPFLink.h"
using namespace System::Runtime::InteropServices;
namespace WPFLink
{
public class WPFPrivate
{
public:
msclr::auto_gcroot<System::String^> inspectionType;
msclr::auto_gcroot<System::String^> testResult;
msclr::auto_gcroot<System::String^> measuredValue;
msclr::auto_gcroot<System::String^> passCondition;
msclr::auto_gcroot<System::String^> comments;
msclr::auto_gcroot<ManagedWPFLink::TestResultsDialog^> testResultDialog;
public:
WPFPrivate()
{
}
~WPFPrivate()
{
delete testResultDialog;
}
};
WPFWrapper::WPFWrapper()
{
this->internalWrapper = new WPFLink::WPFPrivate();
}
WPFWrapper::~WPFWrapper()
{
delete this->internalWrapper;
}
void WPFWrapper::addItems(const char **data)
{
this->internalWrapper->inspectionType = gcnew System::String(data[0]);
this->internalWrapper->testResult = gcnew System::String(data[1]);
this->internalWrapper->measuredValue = gcnew System::String(data[2]);
this->internalWrapper->passCondition = gcnew System::String(data[3]);
this->internalWrapper->comments = gcnew System::String(data[4]);
this->internalWrapper->testResultDialog->addRow(this->internalWrapper->inspectionType, this->internalWrapper->testResult,
this->internalWrapper->measuredValue, this->internalWrapper->passCondition, this->internalWrapper->comments);
}
void WPFWrapper::deleteAllRows()
{
this->internalWrapper->testResultDialog->deleteAllRows();
}
void WPFWrapper::showDialog()
{
this->internalWrapper->testResultDialog->showDialog();
}
}
Native C++ code:
#include "..\WPFLink\WPFLink.h"
int main()
{
WPFLink::WPFWrapper wrapper; // Generates 0xe0434352 error
return 0;
}
After much hair-pulling, I resorted to using the method in this post here: http://www.codeguru.com/cpp/cpp/cpp_managed/nfc/article.php/c14589/Hosting-WPF-Content-in-an-MFC-Application.htm
I used the relevant code to generate an HWND and the program worked flawlessly with my own native C++ code. However, I'm still running into an access violation on startup in our main MFC application which I haven't managed to narrow down at all. The only information I have is that if I attempt to link to my DLL at all, the program crashes. I will have to abandon this method of linking to a stub .lib file and loading the necessary DLL and instead redo the interface to only use extern "C" functions and manually call LoadLibrary on my DLL.
Thanks everyone who tried to help.

Using unmanaged C#-DLL in C++/FORTRAN

I am working on my master thesis and need your help! Btw I am studying mechanical enginneering... so my programming skills are limited.
Here my problem:
I have a DLL, which is created in C# ( I cannot post it, because it is a part of an unpublished research). But it gives me some Arrays ( 1D-Array [], 2DArray[,] ).
For a simulation with ABAQUS I need to import that C#-DLL in C++ and/or FORTRAN.
I found the solution from Robert Giesecke to create a unmanaged DLL. I think this is the easiest solution for me. (Of course if someone has another solution for me, a wrapper or something, please post it)
Here my 1D Array example for a unmanaged C#-DLL created with R.Giesecke Template:
using System;
using System.Text;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
namespace Testme
{
class Test
{
[DllExport("Get1DArray", CallingConvention = CallingConvention.StdCall)]
public static double Get1DArray([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] double[] STRESS, int i)
{
return STRESS[i];
}
}
}
and here my 2D Array code:
using System;
using System.Text;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
namespace Testme
{
class Test
{
public static int idx(int a, int b) { int cols = 2; return a * cols + b; }
[DllExport("Set2DArray", CallingConvention = CallingConvention.StdCall)]
public static int Set2DArray([In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] int[] STRAIN, int len)
{
STRAIN[idx(0, 0)] = 0;
STRAIN[idx(0, 1)] = 1;
STRAIN[idx(1, 0)] = 2;
STRAIN[idx(1, 1)] = 3;
STRAIN[idx(2, 0)] = 4;
STRAIN[idx(2, 1)] = 5;
return 0;
}
}
}
The Build have succeeded at both. How can I import the DLLs in C++ and/or FORTRAN?
Thx in advance!
When you compile your C#-DLL with tool from R. Giesecke, you should also get a *.lib file with it.
You need to reference this lib in your FORTRAN linker settings as additional library dependency. It contains all the code required to load the DLL and make the functions in the DLL available.
In your FORTRAN code you need to declare the imported methods with the following statements:
!DEC$ ATTRIBUTES DLLIMPORT, ALIAS:'_MethodeName::MethodName
BTW: COM visibility is not needed if using RGiesecke. The access to the C# is native and not via COM (also making it considerably faster).

Unity3D load an not exist DLL file , still work but no effect to the result

I tried to integrate my own c++ plugin with Unity3D project. But it doesn't work. So i wrote some small code to test, I found some strange problems, make me #$%##$^##$^#^
First I create a small dll project by code
#include "stdafx.h"
#define EXPORT_API __declspec(dllexport)
extern "C"
{
EXPORT_API void testFloatPoint(float *mFloat)
{
for(int i = 0 ; i<13;i++)
{
*mFloat = (float)i;
mFloat++;
}
mFloat = mFloat-13;
}
}
Then I tried to invoke this dll file in unity3D c# script by following code:
using UnityEngine;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections;
using System.IO;
public class TestDLL : MonoBehaviour
{
float[] pose_float;//
#region import c++ dll
[DllImport ("TestDLL2")]
public static extern void testFloatPoint ([In,Out] float[] pose_float);
#endregion
void Start ()
{
pose_float = new float[13];
testFloatPoint(pose_float);
print ("get pose_float data!!!");
for(int i=0;i<13;i++)
{
print(pose_float[i]);
}
}
}
but the print out msg are all zero. It's a bit strange, because before I got the result is "0,1,2,3....12". I can't figure out where the problem is . So i tried to remove the dll file from my unity3D project folder. Much more strange problem is, it can still run with all zero output result. There is no TestDLL2 file under the project folder and there is no dllnotfound problem.
Is there some advice from U? It bother me around one week , Thank you very much!

Roslyn CTP - How to Write Changes To File System

I created an empty Visual Studio Solution called Solution.sln which I load into the workspace int the first line. Then I add a project to the solution, and update the workspace to the latest solution which should now contain a project. How do I write out the files for the new stuff I added to the empty solution?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
using Roslyn.Services;
namespace RoslynMainApp
{
class Program
{
static void Main(string[] args)
{
IWorkspace workspace = Workspace.LoadSolution(#"C:\RoslynSolutions\Solution.sln");
ProjectId projectId;
ISolution solution = Solution.Create(SolutionId.CreateNewId("Solution"));
solution.AddCSharpProject("Project1.dll", "Project1", out projectId);
var success = workspace.ApplyChanges(workspace.CurrentSolution, solution);
if(success)
{
//How do I write out all the stuff I just added to Solution.sln to the directory RoslynSolutions?
}
}
}
}
Thanks in advance,
Bob
The act of calling ApplyChanges should write the changes to disk. However, note that in CTP1, only a small set of the changes you can apply to solutions are actually implemented.

Categories