My python app is not able to call a method from C# that uses a third party library (namely, Gurobi).
My project structure:
- a C# Library Project that is an Algorithm (in some parts of it I use Gurobi (a library of its own))
- a Python App, which is connected to the C# script by a C# DLL. The connection works for simple method like addition and multiplication.
When I call a more sophisticated method from the C# library in python (i.e. one with a Gurobi method implemented), I am not able run the method and get a FileNotFoundException. I have tried adding the DLL of Gurobi itself but it did not work.
Upon calling the method with the implicit Gurobi code, I get:
How can I add the gurobi DLL and Newtonsoft.Json DLLs to my python code?
- I have tried manually adding the gurobi dll, yet the C# project as a Library output has no gurobi dll within the bin folder (i.e. where the C# library dll is constructed "alnslib.dll").
- I also tried establishing the connection via exe instead of Library, it did not work.
This is my python code:
import clr
# Add references to the DLLs
clr.AddReference("bin/Debug/net7.0/alnslib")
# This attempt did not work
# clr.AddReference("bin/Debug/net7.0/gurobi100.netstandard20.dll")
# import gurobi100
from alnslib import Class1
import streamlit as st
from ctypes import *
import json
st.title('Testing C# DLL')
# Simple Maths Calculation connections
calculator = Class1()
st.write(calculator.Add(5, 5))
st.write(calculator.Multiply(5, 5))
# SumList method
numbers = [1.5, 2.3, 4.7, 3.1]
num_array = (c_double * len(numbers))(*numbers) # This Notation is new
result = calculator.SumList(num_array)
st.write("Sum of the numbers:", result)
# SumList method with a 2x2 matrix
matrix = [
[2.5, 2.5],
[5, 6.0]
]
# Flatten the 2D Python list
flat_matrix = [item for sublist in matrix for item in sublist]
# Convert the flattened Python list to a C-style array of doubles
num_array_2d = (c_double * len(flat_matrix))(*flat_matrix)
# Call the SumList method with the 1D array
result_matrix_sum = calculator.SumList(num_array_2d)
st.write("Sum of the 2D matrix:", result_matrix_sum)
# JSON processing method
json_data = {
"key1": 5,
"Test": 2,
}
# Convert JSON object to a string
json_string = json.dumps(json_data)
# Call the ProcessJson method with the JSON string
result_json_processing = calculator.ProcessJson(json_string)
st.write(result_json_processing)
st.write(calculator.SolveLinearProgrammingProblem())
# st.write(calculator.ProcessJsonStringToJson(json_string))
This is my C# code:
using System;
using Newtonsoft.Json.Linq;
using Gurobi;
namespace alnslib
{
public class Class1
{
// Method to add two numbers
public int Add(int a, int b)
{
return a + b;
}
// Method to multiply two numbers
public int Multiply(int a, int b)
{
return a * b;
}
// Method to sum an array of floating-point numbers
public double SumList(double[] numbers)
{
double sum = 0;
foreach (var number in numbers)
{
sum += number;
}
return sum;
}
// Method to sum a 2D array of floating-point numbers
public double SumListTwo(double[,] matrix)
{
double sum = 0;
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
sum += matrix[i, j];
}
}
return sum;
}
// Method to process a JSON string
public string ProcessJson(string jsonString)
{
// Your processing logic here
return "Processed: " + jsonString;
}
// Method to process a JSON string
public string ProcessJsonStringToJson(string jsonString)
{
// Parse the JSON string to create a JObject
JObject jsonObject = JObject.Parse(jsonString);
// Now you have a JObject to work with
// Your processing logic here
// Example: Add a new key-value pair to the JObject
jsonObject["NewKey"] = "NewValue";
// Convert the modified JObject back to a string
string modifiedJsonString = jsonObject.ToString();
// Return the modified JSON string
return "Processed: " + modifiedJsonString;
}
// Method to solve a simple linear programming problem using Gurobi
public string SolveLinearProgrammingProblem()
{
try
{
using (GRBEnv env = new GRBEnv())
{
// Create a Gurobi model
using (GRBModel model = new GRBModel(env))
{
// Add variables
GRBVar x = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "x");
GRBVar y = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "y");
// Set objective function
GRBLinExpr objExpr = new GRBLinExpr();
objExpr.AddTerm(2.0, x);
objExpr.AddTerm(1.0, y);
model.SetObjective(objExpr, GRB.MAXIMIZE);
// Add constraint: x + 2y <= 1
GRBLinExpr constraintExpr = new GRBLinExpr();
constraintExpr.AddTerm(1.0, x);
constraintExpr.AddTerm(2.0, y);
model.AddConstr(constraintExpr, GRB.LESS_EQUAL, 1.0, "constraint1");
// Optimize the model
model.Optimize();
// Return the solution as a string
return $"Optimal Objective Value: {model.ObjVal}, Optimal x: {x.Get(GRB.DoubleAttr.X)}, Optimal y: {y.Get(GRB.DoubleAttr.X)}";
}
}
}
catch (GRBException e)
{
return $"Error code: {e.ErrorCode}. {e.Message}";
}
}
// Main method to execute the Gurobi linear programming problem solver
public static void Main()
{
Class1 myClass = new Class1();
// Call the Gurobi solver method
string result = myClass.SolveLinearProgrammingProblem();
// Print or log the result
Console.WriteLine(result);
// Optionally, you can wait for user input before closing the console window
Console.WriteLine("Press Enter to exit...");
Console.ReadLine();
}
}
}
This is my C# Project Configuration .csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Gurobi.Optimizer" Version="10.0.3" />
</ItemGroup>
</Project>