我想使用azure函数运行.cmd文件。我想在后台进程而不是azure函数的主进程中运行它。
我已经使用Kudu编辑器将cmd文件保存在azure功能平台上。我可以在本地运行它,但是在部署后根本无法运行(我也没有收到任何错误)。
string cmdFileLocation = @"D:\home\jobs.cmd";
Process proc = new Process();
ProcessStartInfo info = new ProcessStartInfo();
try
{
info.FileName = cmdFileLocation;
info.Arguments = name;
info.WindowStyle = ProcessWindowStyle.Minimized;
info.UseShellExecute = false;
proc.StartInfo = info;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
proc.Start();
proc.WaitForExit();
}
catch (Exception ex)
{
log.LogInformation("Exception Occurred :{0},{1}", ex.Message, ex.StackTrace.ToString());
}
为进行测试,cmd文件中包含curl命令。卷曲将在使用azure函数的本地计算机上触发,因为我可以看到请求即将到来(https://webhook.site),但在执行任何操作后都没有任何反应。
答案 0 :(得分:1)
这是使任何.exe / .cmd作为Web服务运行的简便方法。您只需在配置文件中为exe / cmd指定输入参数。您可以通过指定要下载的URL将二进制文件用作exe的输入。
配置文件如下所示
{
"name": "consoleAppToFunctions",
"input": {
"command": "ffmpeg.exe -i {inputFile} {output1}",
"arguments": {
"inputFile": {
"url": "https://1drv.ms/v/<link-to-file>"
//binary file input
},
"output1": {
"localfile": "out.mp3"
//stored in a temp folder
}
}
},
"output": {
"folder": "outputFolder",
"binaryFile": {
"returnFile": "*.mp3",
"returnFileName": "yourFile.mp3"
}
}
}
以下是相同的AZURE功能代码:
#r "Newtonsoft.Json"
using System.Net;
using Newtonsoft.Json;
using System.IO;
using System.Diagnostics;
//Code from https://github.com/Azure-Samples/functions-dotnet-migrating-console-apps/edit/master/code/run.csx
//Written by Ambrose http://github.com/efficientHacks and Murali http://github.com/muralivp
public class ExeArg
{
public string Name { get; set; }
public string Type { get; set; }
public string Value { get; set; }
}
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
string localPath = req.RequestUri.LocalPath;
string functionName = localPath.Substring(localPath.LastIndexOf('/')+1);
var json = File.ReadAllText(string.Format(@"D:\home\site\wwwroot\{0}\FunctionConfig.json",functionName));
var config = JsonConvert.DeserializeObject<dynamic>(json);
var functionArguments = config.input.arguments;
var localOutputFolder = Path.Combine(@"d:\home\data", config.output.folder.Value, Path.GetFileNameWithoutExtension(Path.GetTempFileName()));
Directory.CreateDirectory(localOutputFolder);
var workingDirectory = Path.Combine(@"d:\home\site\wwwroot", functionName + "\\bin");
Directory.SetCurrentDirectory(workingDirectory);//fun fact - the default working directory is d:\windows\system32
var command = config.input.command.Value;
var argList = new List<ExeArg>();
//Parse the config file's arguments
//handle file system, local file etc. and construct the input params for the actual calling of the .exe
foreach (var arg in functionArguments)
{
var exeArg = new ExeArg();
exeArg.Name = arg.Name;
var value = (Newtonsoft.Json.Linq.JObject)arg.Value;
var property = (Newtonsoft.Json.Linq.JProperty)value.First;
exeArg.Type = property.Name;
exeArg.Value = property.Value.ToString();
var valueFromQueryString = await getValueFromQuery(req, exeArg.Name);
log.Info("valueFromQueryString name=" + exeArg.Name);
log.Info("valueFromQueryString val=" + valueFromQueryString);
if(!string.IsNullOrEmpty(valueFromQueryString))
{
exeArg.Value = valueFromQueryString;
log.Info(exeArg.Name + " " + valueFromQueryString);
}
if(exeArg.Type.ToLower() == "localfile" || exeArg.Type.ToLower() == "localfolder")
{
exeArg.Value = Path.Combine(localOutputFolder, exeArg.Value);
exeArg.Type = "string";
}
if(string.IsNullOrEmpty(exeArg.Value))
{
//throw exception here
}
argList.Add(exeArg);
}
//call the exe
Dictionary<string, string> paramList = ProcessParameters(argList, localOutputFolder);
foreach (string parameter in paramList.Keys)
{
command = command.Replace(parameter, paramList[parameter]);
}
string commandName = command.Split(' ')[0];
string arguments = command.Split(new char[] { ' ' }, 2)[1];
log.Info("the command is " + command);
log.Info("the working dir is " + workingDirectory);
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = commandName;
p.StartInfo.Arguments = arguments;
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
File.WriteAllText(localOutputFolder+"\\out.txt",output);
//handle return file
log.Info("handling return file localOutputFolder=" + localOutputFolder);
string outputFile = config.output.binaryFile.returnFile.Value;
string outputFileName = config.output.binaryFile.returnFileName.Value;
var path = Directory.GetFiles(localOutputFolder, outputFile)[0];
log.Info("returning this file " + path);
var result = new FileHttpResponseMessage(localOutputFolder);
var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = outputFileName
};
return result;
}
private static Dictionary<string, string> ProcessParameters(List<ExeArg> arguments, string outputFolder)
{
Dictionary<string, string> paramList = new Dictionary<string, string>();
foreach (var arg in arguments)
{
switch (arg.Type)
{
case "url":
string downloadedFileName = ProcessUrlType((string)arg.Value, outputFolder);
paramList.Add("{" + arg.Name + "}", downloadedFileName);
break;
case "string":
paramList.Add("{" + arg.Name + "}", arg.Value.ToString());
break;
default:
break;
}
}
return paramList;
}
//you can modify this method to handle different URLs if necessary
private static string ProcessUrlType(string url, string outputFolder)
{
Directory.CreateDirectory(outputFolder);
string downloadedFile = Path.Combine(outputFolder, Path.GetFileName(Path.GetTempFileName()));
//for oneDrive links
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(url);
webRequest.AllowAutoRedirect = false;
WebResponse webResp = webRequest.GetResponse();
webRequest = (HttpWebRequest)HttpWebRequest.Create(webResp.Headers["Location"].Replace("redir", "download"));
webResp = webRequest.GetResponse();
string fileUrl = webResp.Headers["Content-Location"];
WebClient webClient = new WebClient();
webClient.DownloadFile(fileUrl, downloadedFile);
return downloadedFile;
}
private async static Task<string> getValueFromQuery(HttpRequestMessage req, string name)
{
// parse query parameter
string value = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, name, true) == 0)
.Value;
//if not found in query string, look for it in the body (json)
// Get request body
dynamic data = await req.Content.ReadAsAsync<object>();
// Set name to query string or body data
value = value ?? data?[name];
return value;
}
//this is to delete the folder after the response
//thanks to: https://stackoverflow.com/a/30522890/2205372
public class FileHttpResponseMessage : HttpResponseMessage
{
private string filePath;
public FileHttpResponseMessage(string filePath)
{
this.filePath = filePath;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
Content.Dispose();
Directory.Delete(filePath,true);
}
}
在这里您可以找到更多关于this的信息。希望对您有所帮助。