1
\$\begingroup\$

Description

I've been attempting to use a custom DLL in Unity. I've confirmed the DLL runs correctly outside Unity.

The DLL imports into Unity and when I refer to it in my scripts, I get no compiler errors. However, trying to run a function from the DLL at runtime gives this error:

InvalidOperationException: Client endpoint configuration '*' was not found in 0 endpoints.
System.ServiceModel.ChannelFactory.ApplyConfiguration (System.String endpointConfig)
System.ServiceModel.ChannelFactory.InitializeEndpoint (System.String endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress)
System.ServiceModel.ChannelFactory`1[DNDUtility.ContentVaultServiceTest.IContentVaultService]..ctor (System.String endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress)
System.ServiceModel.ClientBase`1[TChannel].Initialize (System.ServiceModel.InstanceContext instance, System.String endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress)
System.ServiceModel.ClientBase`1[TChannel]..ctor (System.ServiceModel.InstanceContext instance, System.String endpointConfigurationName)
System.ServiceModel.ClientBase`1[TChannel]..ctor (System.ServiceModel.InstanceContext instance)
System.ServiceModel.ClientBase`1[TChannel]..ctor ()
DNDUtility.ContentVaultServiceTest.ContentVaultServiceClient..ctor ()
DNDUtility.DataManager..cctor ()
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for DNDUtility.DataManager
TestStuff.OnGUI () (at Assets/TestStuff.cs:39)

I've tried compiling the DLL with .NET 4, 4.5, 3.5, and 2. (I can provide the DLL file if needed.)

What causes this?

Code listings

DLL code

using System;
using System.Xml.Linq;
using System.Security.Cryptography;
using System.Text;
using System.IO;

namespace DNDUtility
{
    using ContentVaultServiceTest;

    public class DataManager
    {
        static ContentVaultServiceClient contentClient = new ContentVaultServiceClient();

        public static bool Login(string user, string pass)
        {
            return contentClient.Login(user,
                SimpleEncrypt(pass, user));
        }

        public static string[] GetChars()
        {
            ContentInfo[] content = contentClient.GetAvailableContent(0);

            string[] chars = new string[content.Length];

            for (int i = 0; i < content.Length; i++)
            {
                XDocument doc = XDocument.Parse(content[i].CommittedContent.Details.ToString());
                var name = doc.Element("CharacterDetails").Element("Name").Value;

                chars[i] = string.Format("{0} : {1}", i, name);
            }

            return chars;
        }

        public static void GetData()
        {
            ContentInfo[] content = contentClient.GetAvailableContent(0);

            DataWithVersion data = contentClient.GetData(
                new ContentIdentifier() { ContentID = content[0].CommittedContent.Identifier.ContentID },
                null);

            RawContentBlob blob = data.Data as RawContentBlob;

            String charFile = new UTF8Encoding().GetString(blob.RawData, 0, blob.RawData.Length);

            XDocument doc = XDocument.Parse(charFile);
            doc.Save("d:\Users\Tim Williams\Desktop\Work Documents\TerabyteTim\DND App\ContentVault\ConsoleApplication1\contentdoc.xml");
        }

        public static byte[] SimpleEncrypt(string value, string key)
        {
            byte[] buffer2;
            ICryptoTransform transform = GetSimpleAlgorithm(key).CreateEncryptor();
            using (MemoryStream stream = new MemoryStream())
            {
                using (CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Write))
                {
                    byte[] bytes = Encoding.UTF8.GetBytes(value);
                    stream2.Write(bytes, 0, bytes.Length);
                    stream2.Flush();
                    stream2.FlushFinalBlock();
                    stream.Position = 0L;
                    buffer2 = stream.ToArray();
                }
            }
            return buffer2;
        }

        static SymmetricAlgorithm GetSimpleAlgorithm(string key)
        {
            AesManaged aes = new AesManaged();
            byte[] source = new SHA256Managed().ComputeHash(Encoding.UTF8.GetBytes(key));

            byte[] take = new byte[aes.BlockSize / 8];
            for (int i = 0; i < aes.BlockSize / 8; i++)
            {
                take[i] = source[i];
            }

            return new AesManaged { Key = source, IV = take };
        }
    }}

Unity C# script

This script tries to access the DLL.

using System;
using System.Runtime.InteropServices;
using DNDUtility;
using UnityEngine;
using System.Collections;

public class TestStuff : MonoBehaviour
{
    void OnGUI()
    {
        if (GUI.Button(new Rect(0, 0, 100, 100), "Login"))
        {
            Debug.Log(DataManager.Login("username", "password"));
        }

        if (GUI.Button(new Rect(125, 0, 100, 100), "Get Characters"))
        {
            string[] chars = DataManager.GetChars();

            for (int i = 0; i < chars.Length; i++)
            {
                Debug.Log(chars[i]);
            }
        }
    }
}

You can find the ContentVaultServiceTest at this Pastebin.

DNDUtility App.config code

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="CustomBinding_IContentVaultService" maxReceivedMessageSize="200000000"
                    allowCookies="true">
                    <security mode="None" />
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://ioun.wizards.com/ContentVault.svc"
                binding="wsHttpBinding" bindingConfiguration="CustomBinding_IContentVaultService"
                contract="ContentService.IContentVaultService" name="CustomBinding_IContentVaultService" />
        </client>
    </system.serviceModel>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>

I've tried multiple different settings for the contentClient:

static string endpointConfigurationName = "CustomBinding_IContentVaultService";
        static EndpointAddress remoteAddress = new EndpointAddress("http://ioun.wizards.com/ContentVault.svc");
        static ContentVaultServiceClient contentClient = new ContentVaultServiceClient(endpointConfigurationName, remoteAddress);

static WSHttpBinding customBinding = new WSHttpBinding() { AllowCookies = true, MaxReceivedMessageSize = 200000000, Name = "CustomBinding_IContentVaultService" };
        static EndpointAddress remoteAddress = new EndpointAddress("http://ioun.wizards.com/ContentVault.svc");
        static ContentVaultServiceClient contentClient = new ContentVaultServiceClient(customBinding, remoteAddress);

When used in an external project without an App.config (using the first solution) I get this error:

Exception:Thrown: "Could not find endpoint element with name 'CustomBinding_IContentVaultService' and contract 'ContentService.IContentVaultService' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this name could be found in the client element." (System.InvalidOperationException)
A System.InvalidOperationException was thrown: "Could not find endpoint element with name 'CustomBinding_IContentVaultService' and contract 'ContentService.IContentVaultService' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this name could be found in the client element."
Time: 4/13/2014 2:07:22 PM
Thread:<No Name>[7520]

Using the second solution, I get:

Exception:Caught: "Secure channel cannot be opened because security negotiation with the remote endpoint has failed. This may be due to absent or incorrectly specified EndpointIdentity in the EndpointAddress used to create the channel. Please verify the EndpointIdentity specified or implied by the EndpointAddress correctly identifies the remote endpoint. " (System.ServiceModel.Security.SecurityNegotiationException)
A System.ServiceModel.Security.SecurityNegotiationException was caught: "Secure channel cannot be opened because security negotiation with the remote endpoint has failed. This may be due to absent or incorrectly specified EndpointIdentity in the EndpointAddress used to create the channel. Please verify the EndpointIdentity specified or implied by the EndpointAddress correctly identifies the remote endpoint. "
Time: 4/13/2014 2:35:38 PM
Thread:<No Name>[1356]

What should I set the EndpointIdentity to?

\$\endgroup\$
  • \$\begingroup\$ Does this 'Unity' framework/tool use any kind of app.config or web.config? \$\endgroup\$ – Den Apr 1 '14 at 19:30
  • \$\begingroup\$ Yes the DLL does use an app.config. \$\endgroup\$ – Timothy Williams Apr 1 '14 at 19:31
  • \$\begingroup\$ the utility svcutil.exe creates a config file its looking for. maybe it is in the wrong location? \$\endgroup\$ – Stephan van den Heuvel Apr 2 '14 at 2:45
  • 1
    \$\begingroup\$ DLLs for Unity should be compiled using .NET 3.5. Unity supports .NET 2 and some of .NET 3.5, but there might be gaps (just what happened to us – DLL compiles fine with NET 3.5, but refuses to run in Unity, since some function it depends on is simply not implemented in Mono yet). \$\endgroup\$ – xeophin Apr 2 '14 at 6:53
  • \$\begingroup\$ Stephan: Where would I find that config file? Xeophin: I tried compiling for .NET 3.5 and still got errors, and I believe some of the functions wouldn't work in the DLL when I changed the .NET to 2 \$\endgroup\$ – Timothy Williams Apr 2 '14 at 14:45
1
+100
\$\begingroup\$

It looks like the endpoint configuration in your app.config is missing in Unity. The exception points to the "ctor" or constructor. The fact that it errors on the "InvalidOperationException: Client endpoint configuration '*' was not found in 0 endpoints." makes me believe that it cant find the configuration for that endpoint. It probably needs that, so that it can make the secure connection.

So, if it were a problem I needed to solve, i would start by looking at how to use the configuration in the app.config file, in my unity project.

This exception doesnt relate directly to the fact that the dll is compiled against the wrong .NET version, it relates to the configuration of the endpoint only.

EDIT:

if you look at the instancing of the contentClient:

public class DataManager { static ContentVaultServiceClient contentClient = new ContentVaultServiceClient();

you're simply calling the default constructor, but, the class has several constructors of choice, namely:

    public ContentVaultServiceClient(string endpointConfigurationName)
    public ContentVaultServiceClient(string endpointConfigurationName, string remoteAddress)
    public ContentVaultServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress)
    public ContentVaultServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress)

so, you could ignore the requirement for an app.config, and simply pass in a string for the configurationname and endpoint, such as an endpoint written as eg: "http......". Im not sure how the configurationname should be written, you will need to look at that within your app.config and paste it as a string:

    string endpointConfigurationName = "someEndpointConfigurationName";
    string remoteAddress = "http......";
    static ContentVaultServiceClient contentClient = new ContentVaultServiceClient(endpointConfigurationName, remoteAddress);

EDIT 2:

It looks like the ContentVaultServiceClient is implementing the IContentVaultService, therefore we could write something like:

BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress("http://ioun.wizards.com/ContentVault.svc");

ContentVaultServiceClient contentClient = new ContentVaultServiceClient(binding, address);

If we look inside the ContentVaultServiceClient class, we can see a constructor that accepts both binding and endpointaddress parameters:

public ContentVaultServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
                base(binding, remoteAddress) {
        }

I would like to say that the errors you are getting have now changed from the first post you made, which highlights now the fact that it is becoming a service configuration problem in .NET now, and no longer an issue with trying to get DLLs working in Unity.

I would strongly suggest that this question is not drawn out any more, as it deviates from the original question too much, and might confuse readers in the future.

You're more than welcome to contact me directly on Skype, at coombes.jason, where I will help you further if you need.

\$\endgroup\$
  • \$\begingroup\$ Hmm I'm not seeing any configuration information for Unity. Unity doesn't appear to use any config files. Would there be a way to store the configuration in the DLL file? Or have the DLL file load an external config file at runtime? \$\endgroup\$ – Timothy Williams Apr 9 '14 at 14:48
  • \$\begingroup\$ I edited my answer for you \$\endgroup\$ – Jason Coombes Apr 10 '14 at 13:19
  • \$\begingroup\$ I've attempted to do what you suggested, I edited my question with the code I tried and the errors it threw. I've been using a new console project as a safe environment to test this in, it works fine with an App.config, but when trying what you suggested it throws errors about the endpoints. Any ideas? Thanks a ton for the help so far! \$\endgroup\$ – Timothy Williams Apr 13 '14 at 18:13
  • \$\begingroup\$ Second edit. Hope it works for you. \$\endgroup\$ – Jason Coombes Apr 14 '14 at 5:03
  • \$\begingroup\$ The DLL now works with Unity. The only issue I'm having is Unity won't allow the DLL to save cookies for the login session. However I've marked the answer as correct and awarded the bounty because this did solve the initial issue. \$\endgroup\$ – Timothy Williams Apr 15 '14 at 16:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.