Running C# in CodeRunner

Re: Running C# in CodeRunner

by Martin Zwerschke -
Number of replies: 4

I did it this way (Prototype for question to create a c#-function):

""" The template for a question type that compiles and runs a student-submitted
    mono C# program. 
"""

import subprocess, sys

# Write the student code to a file prog.cs
student_answer = """using System;using System.IO;using System.Text;namespace myProg {    class program {"""
student_answer += """ {{ STUDENT_ANSWER | e('py') }} """
student_answer += """ public static void Main(string[] args) { """
student_answer += """ {{TEST.testcode | e('py') }}"""
student_answer += """ } } } """

with open("prog.cs", "w") as src:
    print(student_answer, file=src)

# Compile
return_code = subprocess.call(['mcs', 'prog.cs'])
if return_code != 0:
    print("** Compilation failed. Testing aborted **", file=sys.stderr)

# If compile succeeded, run the code. Since this is a per-test template,
# stdin is already set up for the stdin text specified in the test case,
# so we can run the compiled program directly.
if return_code == 0:
    try:
        output = subprocess.check_output(["mono", "./prog.exe"], universal_newlines=True)
        print(output)
    except subprocess.CalledProcessError as e:
        if e.returncode > 0:
            # Ignore non-zero positive return codes
            if e.output:
                print(e.output)
        else:
            # But negative return codes are signals - abort
            if e.output:
                print(e.output, file=sys.stderr)
            if e.returncode < 0:
                print("Task failed with signal", -e.returncode, file=sys.stderr)
            print("** Further testing aborted **", file=sys.stderr)

For example you ask your students to write a function that calculates the average of three values.

The Question for the students is:


Please write a C#-Function  (private static oder public static does not matter),

that calculates the average value of 3 Numbers (type int) and returns it as a float value.

Please only put this function into the answer box (and nothing else) !

Moodle calls your function and tests the result.


And they just have to fill this function into the answer-box.

The correct answer could be like this:

public static float Average(int a, int b, int c)
{
            int sum = a + b + c;

            return sum / 3.0f; 
}

Then use test cases like:

Console.Write(Average(3,4,2));

with expexted output of 3

or

Console.Write(Average(5,8,12));

with expected output of 8.333333


This workes for me, though I not really know, why the 

| e('py') 

is necessary. I just copied it from Robb's sample above.


Hope that will help you.


In reply to Martin Zwerschke

Re: Running C# in CodeRunner

by Richard Lobb -

Hi Martin

Thanks for posting. Just to answer your question about why the | e('py') is necessary....

When wrapping a raw string from the author form or student answer in quotes to make a literal string within the template code, you generally need to escape various special characters that might result in invalid string literals. As a trivial example, if a student's answer was "Hi" (including the double quotes) and you wrote, in JavaScript.

s = "{{STUDENT_ANSWER}}";

you'd get

s = ""Hi"";

which is broken. Hence Twig provides a range of escapers, so that for a JavaScript template you can write

s = "{{STUDENT_ANSWER | e('js')}}"

which would give you the valid

s = "\"Hi\"";

I've added to the Twig base set of escapers, e('py'), e('java') and e('matlab'). The Java escaper can be used for C and C++ too. 

The Python escaper is intended for use only within triple-quoted string literals. It escapes only double quotes (in case the raw string itself has triple quotes in it) and backslashes. Backslashes need to be escaped so that, for example, a 2-character \n in the student's code doesn't get converted to a single newline character in the triple-quoted literal.

Richard


In reply to Richard Lobb

Re: Running C# in CodeRunner

by Martin Zwerschke -

Hi Richard,

we are using C#  under coderunner using "mono" and the c#-via python prototype for a while now - works like a charme.

Now  I tried to use C# 7 features (like the "switch-case" pattern match with keyword "when")

mcs C# compiler is called in the prototype. But it does not understand "when" keyword.

I tried to add option -langversion:7.2  (which mcs can handle) but it still does not support "when"

So i tried to switch to  newer  "csc"  compiler , that can handle "when" and other C#7 features.

I used:

return_code = subprocess.call(['csc', '/unsafe+', '/nologo', '-langversion:latest', 'prog.cs'])

for the compilation. It seems to work.

But the code execution runs into runtime exceptions:

"Unhandled Exception:

[ERROR] FATAL UNHANDLED EXCEPTION: System.OutOfMemoryException: Out of memory
at (wrapper managed-to-native) System.Runtime.InteropServices.Marshal.AllocHGlobal(intptr)"

OutOfMemoryException


But if i use 

mono ./test.exe

to execute the csc-generated compilation on the jobe server's command line, the program executes without problems though.

Does jobe block the code?


In reply to Martin Zwerschke

Re: Running C# in CodeRunner

by Richard Lobb -

Jobe sets resource limits (processes, cpu time, memory, file output) on all tasks. It seems you have hit the default limit on memory, presumably because the newer C# version wants more memory than the older one. With this question type, which runs C# in a subprocess, you need enough memory for both Python and C# together. Depending on what version you're running, the default is somewhere between 300 MB and 500 MB as I recall.

Easily fixed. In your prototype, open the Advanced Customisation panel and experiment with the setting of the Memory Limit field. A value of 0 turns off the memory limit checking altogether so you may want to try this first, but that's not recommended as a permanent setting.

In reply to Richard Lobb

Re: Running C# in CodeRunner

by Martin Zwerschke -

Increasing the memory limit did the trick.


I was suprised, however, that the csc compiler needs so much memory.

I had to increase to at least 600MB to succeed and now use a limit of 650MB for my C#-questions prototype.

Of course it is not only csc that uses the memory but the whole jobe toolchain.

At least csc needs much more memory than mcs does.

(Perhaps because it comes from Microsoft...)

Thanks for your help.