R の関数を C# から使う - WebService 編


R の関数を C# から使う」では自分の PC 上の DLL を叩いて実行するという方法を行いました。今回は ideone.com の API を叩いて結果を頂戴するという方法を紹介します[A]

Ideone API に C# のサンプルコードがあるのでそれを利用すると簡単なのですが, 1 箇所誤りがあります。 Ideone_ServiceService.cs の createSubmission メソッドの 3 つ目の引数の名前が source_code になっていますが,これを sourceCode に修正する必要があります。

とりあえず動かすのに必要な部分だけを抜き出せば次のようになります。ただし,見やすさのために少し変更を加えてます。

[GeneratedCode("wsdl", "2.0.50727.3038")]
[WebServiceBinding(Name = "Ideone_ServiceBinding", Namespace = "http://ideone.com/api/1/service")]
public partial class IdeoneClient : SoapHttpClientProtocol
{
	public IdeoneClient()
	{
		this.Url = "http://ideone.com/api/1/service";
	}

	[SoapRpcMethod("http://ideone.com/api/1/service#createSubmission", RequestNamespace = "http://ideone.com/api/1/service", ResponseNamespace = "http://ideone.com/api/1/service")]
	[return: SoapElement("return")]
	public object[] createSubmission(string user, string pass, string sourceCode, int language, string input, bool run, bool @private)
	{
		object[] parameters = new object[] { user, pass, sourceCode, language, input, run, @private };
		object[] results = this.Invoke("createSubmission", parameters);
		return (object[])results[0];
	}

	[SoapRpcMethod("http://ideone.com/api/1/service#getSubmissionStatus", RequestNamespace = "http://ideone.com/api/1/service", ResponseNamespace = "http://ideone.com/api/1/service")]
	[return: SoapElement("return")]
	public object[] getSubmissionStatus(string user, string pass, string link)
	{
		object[] parameters = new object[] { user, pass, link };
		object[] results = this.Invoke("getSubmissionStatus", parameters);
		return (object[])results[0];
	}

	[SoapRpcMethod("http://ideone.com/api/1/service#getSubmissionDetails", RequestNamespace = "http://ideone.com/api/1/service", ResponseNamespace = "http://ideone.com/api/1/service")]
	[return: SoapElement("return")]
	public object[] getSubmissionDetails(string user, string pass, string link, bool withSource, bool withInput, bool withOutput, bool withStderr, bool withCmpinfo)
	{
		object[] parameters = new object[] { user, pass, link, withSource, withInput, withOutput, withStderr, withCmpinfo };
		object[] results = this.Invoke("getSubmissionDetails", parameters);
		return (object[])results[0];
	}
}

R の言語コードは 117 です[B]。他の言語の場合も getLanguages で取得できます。後は Ideone API Documentation の通りに行います。まずソースコードをコミットして,結果が出るまで待機して,結果が出たらそれを取得します。

using (IdeoneClient client = new IdeoneClient())
{
	const int RLanguage = 117;
	string source = "\"Hello ideone.com\"";
	var submission = client.createSubmission("test", "test", source, RLanguage, null, true, true);
	var submissionResult = ToDictionary(submission);
	if (submissionResult["error"] == "OK")
	{
		string link = submissionResult["link"];

		do
		{
			Thread.Sleep(3000);
			var status = client.getSubmissionStatus("test", "test", link);
			var statusResult = ToDictionary(status);

			if (statusResult["error"] != "OK")
			{
				Console.Error.WriteLine("Status Error: {0}", submissionResult["error"]);
				break;
			}
			else if (int.Parse(statusResult["status"]) != 0)
			{
				continue;
			}
		} while (false);

		var details = client.getSubmissionDetails("test", "test", link, false, false, true, true, false);
		var detailsResult = ToDictionary(details);

		if (detailsResult["error"] == "OK")
		{
			string output = detailsResult["output"];
			if (!string.IsNullOrEmpty(output))
			{
				Console.WriteLine(output);
			}

			string stderr = detailsResult["stderr"];
			if (!string.IsNullOrEmpty(stderr))
			{
				Console.Error.WriteLine(stderr);
			}
		}
		else
		{
			Console.Error.WriteLine("Details Error: {0}", submissionResult["error"]);
		}
	}
	else
	{
		Console.Error.WriteLine("Submission Error: {0}", submissionResult["error"]);
	}
}

private static Dictionary<string, string> ToDictionary(object[] result)
{
	var dictionary = new Dictionary<string, string>();
	foreach (var e in result.OfType<XmlElement>())
	{
		XmlNodeList list = e.ChildNodes;
		dictionary.Add(list.Item(0).InnerText, list.Item(1).InnerText);
	}
	return dictionary;
}

このままだと使いづらいので,もう少し修正の余地はありますが,試すのには十分でしょう。

脚注

  1. Ideone API © by Sphere Research Labs []
  2. Frequently asked questions []