Main Content

Access Remotable .NET Assembly Using Native .NET API: Cell and Struct

Why Use the .NET API with Cell Arrays and Structs?

Using .NET representations of MATLAB® struct and cell arrays is recommended if both of these are true:

  • You have MATLAB functions on a server with MATLAB struct or cell data types as inputs or outputs

  • You do not want or need to install MATLAB Runtime on your client machines

The native MWArray, MWStructArray, and MWCellArray classes are members of the MathWorks.MATLAB.NET.Arrays.native namespace.

The class names in this namespace are identical to the class names in MathWorks.MATLAB.NET.Arrays. The difference is that the native representations of struct and cell arrays have no methods or properties that require MATLAB Runtime.

The matlabroot\toolbox\dotnetbuilder\Examples\VSVersion\NET folder has example solutions you can practice building. The NativeStructCellExample folder contains native struct and cell examples.

Building Your Component

This example demonstrates how to deploy a remotable component using native struct and cell arrays. Before you set up the remotable client and server code, build a remotable component using the instructions in Create Remotable .NET Assembly.

The Native .NET Cell and Struct Example

The server application hosts the remote component.

The client application, running in a separate process, accesses the remote component hosted by the server application. Build the server with the Microsoft® Visual Studio® project file NativeStructCellServer.csproj:

  1. Change the references for the generated component assembly to component_name\for_redistribution_files_only\component_nameNative.dll.

  2. Select the appropriate build platform.

  3. Select Debug or Release mode.

  4. Build the NativeStructCellServer project.

  5. Supply the configuration file for the NativeStructCellServer. The C# code for the server is in the file NativeStructCellServer.cs:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.Remoting;
    
    namespace NativeStructCellServer
    {
      class NativeStructCellServer
         {
           static void Main(string[] args)
            {
               RemotingConfiguration.Configure(
                                 @"NativeStructCellServer.exe.config");
    
               Console.WriteLine("NativeStructCell Server started...");
    
               Console.ReadLine();
            }
         }
    }
    
    This code reads the associated configuration file to determine:

    • Name of the component to host

    • Remoting protocol and message formatting to use

    • Lease time for the remote component

    In addition, the code also signals that the server is active and waits for a carriage return before terminating.

Coding and Building the Client Application and Configuration File

The client application, running in a separate process, accesses the remote component running in the server application built in The Native .NET Cell and Struct Example. Build the remote client using the Microsoft Visual Studio project file NativeStructCellClient\NativeStructCellClient.csproj. To create the remote client using Microsoft Visual Studio:

  1. Change the references for the generated component assembly to component_name\for_redistribution_files_only\component_nameNative.dll.

  2. Change the references for the generated interface assembly to component_name\for_redistribution_files_only\Icomponent_nameNative.dll.

  3. Select the appropriate build platform.

  4. Select Debug or Release mode.

  5. Build the NativeStructCellClient project.

  6. Supply the configuration file for the NativeStructCellClient.

NativeStructCellClient Code

The C# code for the client is in the file NativeStructCellClient\NativeStructCellClient.cs:

 NativeStructCellClient.cs

This code does the following:

  • The client reads the associated configuration file to get the name and location of the remotable component.

  • The client instantiates the remotable object using the static Activator.GetObject method

  • From this point, the remoting client calls methods on the remotable component exactly as it would call a local component method.

NativeStructCellClient Configuration File

The configuration file for the NativeStructCellClient is in the file NativeStructCellClient\NativeStructCellClient.exe.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="NativeStructCellServer" value=
              "tcp://localhost:1236/NativeStructCellClass.remote"/>    
  </appSettings>
  <system.runtime.remoting>
    <application>
      <channels>
        <channel name="NativeStructCellChannel" ref="tcp" port="0">        
          <clientProviders>            
            <formatter ref="binary" />
          </clientProviders>
          <serverProviders>            
            <formatter ref="binary" typeFilterLevel="Full" />
          </serverProviders>            
        </channel>
      </channels>
    </application>
  </system.runtime.remoting>
</configuration>

This code specifies:

  • Name of the remote component server and the remote component URI (uniform resource identifier)

  • Remoting protocol (TCP/IP) and port number

  • Message formatter (binary) and the permissions for the communication channel (full trust)

Starting the Server Application

Start the server by doing the following:

  1. Open a DOS or UNIX® command window and navigate to NativeStructCellServer\bin\x86\v4.0\Debug.

  2. Run NativeStructCellServer.exe. The following output appears:

    EVENT 1: Initializing the structure on server and sending 
             it to client:
            Initialized empty structure:
    
          Name: ' '
       Address: []
    
    
    ##################################
    
    EVENT 3: Partially initialized structure as 
             received by server:
    
          Name: ' '
       Address: [1x1 struct]
    
    Address field as initialized from the client:
    
       Street: '3, Apple Hill Drive'
         City: 'Natick'
        State: 'MA'
          Zip: '01760'
    
    ##################################
    
    EVENT 4: Updating 'Name' field before sending the 
             structure back to the client:
    
          Name: 'The MathWorks'
       Address: [1x1 struct]
    
    
    ##################################
    

Starting the Client Application

Start the client by doing the following:

  1. Open a DOS or UNIX command window and navigate to NativeStructCellClient\bin\x86\v4.0\Debug.

  2. Run NativeStructCellClient.exe. After MATLAB Runtime initializes, the following output appears:

    EVENT 2: Initialized structure as 
             received in client applications:
    
    1x1 struct array with fields:
           Name
           Address
    
    Updating the 'Address' field to :
    
    1x1 struct array with fields:
           Street
           City
           State
           Zip
    
    #################################
    
    
    EVENT 5: Final structure as received by client:
    
    1x1 struct array with fields:
           Name
           Address
    
    Address field:
    
    1x1 struct array with fields:
           Street
           City
           State
           Zip
    
    #################################
    

Coding and Building the Client Application and Configuration File with the Native MWArray, MWStructArray, and MWCellArray Classes

createEmptyStruct.m

Initialize the structure on the server and send it to the client with the following MATLAB code:

function PartialStruct = createEmptyStruct(field_names)

fprintf('EVENT 1: Initializing the structure on server 
                         and sending it to client:\n');

PartialStruct = struct(field_names{1},' ',field_names{2},[]);

fprintf('         Initialized empty structure:\n\n');
disp(PartialStruct);
fprintf('\n##################################\n');

updateField.m

Receive the partially updated structure from the client and add more data to it, before passing it back to the client, with the following MATLAB code:

function FinalStruct = updateField(st,field_name)

fprintf('\nEVENT 3: Partially initialized structure as 
                              received by server:\n\n');
disp(st);
fprintf('Address field as initialized from the client:\n\n');
disp(st.Address);
fprintf('##################################\n');

fprintf(['\nEVENT 4: Updating ''', field_name, ''' 
   field before sending the structure back to the client:\n\n']);
st.(field_name) = 'The MathWorks';
FinalStruct = st;
disp(FinalStruct);
fprintf('\n##################################\n');

NativeStructCellClient.cs

Create the client C# code:

Note

In this case, you do not need MATLAB Runtime on the system path.

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Configuration;
using MathWorks.MATLAB.NET.Arrays.native;

using INativeStructCellCompNative;

// This is a simple example that demonstrates the use of 
//     MathWorks.MATLAB.NET.Arrays.native package. 
namespace NativeStructCellClient
{
    class NativeStructCellClient
    {
        static void Main(string[] args)
        {
            try
            {
                RemotingConfiguration.Configure
                      (@"NativeStructCellClient.exe.config");
                String urlServer =
                      ConfigurationSettings.AppSettings[
                                                     "NativeStructCellServer"];
                INativeStructCellClassNative nativeStructCell = 
                      (INativeStructCellClassNative)Activator.GetObject(typeof
                           (INativeStructCellClassNative), 
                           urlServer);

                MWCellArray field_names = new MWCellArray(1, 2);
                field_names[1, 1] = "Name";
                field_names[1, 2] = "Address"; 

                Object[] o = nativeStructCell.createEmptyStruct(1,field_names);
                MWStructArray S1 = (MWStructArray)o[0];
                Console.WriteLine("\nEVENT 2: Initialized structure as received 
                                     in client applications:\n\n{0}" , S1);

                //Convert "Name" value from char[,] to a string since 
                // there's no MWCharArray constructor 
                // on server that accepts char[,] as input.
                char c = ((char[,])S1["Name"])[0, 0];
                S1["Name"] = c.ToString();                

                MWStructArray address = 
                      want new MWStructArray(new int[] { 1, 1 }, 
                             new String[] { "Street", "City", "State", "Zip" });
                address["Street", 1] = "3, Apple Hill Drive";
                address["City",   1] = "Natick";
                address["State",  1] = "MA";
                address["Zip",    1] = "01760";

                Console.WriteLine("\nUpdating the 
                                   'Address' field to :\n\n{0}", address);
                Console.WriteLine("\n#################################\n");
                S1["Address",1] = address;

                Object[] o1 = nativeStructCell.updateField(1, S1, "Name");
                MWStructArray S2 = (MWStructArray)o1[0];

                Console.WriteLine("\nEVENT 5: Final structure as received by 
                                     client:\n\n{0}" , S2); 
                Console.WriteLine("\nAddress field: \n\n{0}" , S2["Address",1]);
                Console.WriteLine("\n#################################\n");
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message);
            }
            Console.ReadLine();
        }
    }
}

NativeStructCellServer.cs

Create the server C# code:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;

namespace NativeStructCellServer
{
    class NativeStructCellServer
    {
        static void Main(string[] args)
        {
            RemotingConfiguration.Configure(
                              @"NativeStructCellServer.exe.config");

            Console.WriteLine("NativeStructCell Server started...");

            Console.ReadLine();
        }
    }
}