You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker中.NET API调用Python脚本遇依赖缺失及进程启动错误

问题描述

项目文件夹结构

.
└── root/
    ├── ExRate_Service/
    │   ├── MyOwnPythonScripts... 
    │   └── Program.py
    ├── ExRate_API/
    │   ├── ExRate_API/
    │   │   ├── Classes...
    │   │   ├── ExRate_API.csproj
    │   │   └── Program.cs
    │   ├── ExRate_API.Tests/
    │   │   └── Tests...
    │   └── ExRate_API.sln
    └── Dockerfile

Dockerfile内容

FROM python:3.9.10-slim-buster AS build
WORKDIR /app
RUN pip install numpy pandas requests python-dotenv tensorflow scikit-learn keras matplotlib
COPY ./ExRate_Service .
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS package
WORKDIR /app
COPY ExRate_API .
RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS final
WORKDIR /app
COPY --from=build /app ExRate_Service
COPY --from=build /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages
COPY --from=package /app/out ExRate_API
ENTRYPOINT ["dotnet", "ExRate_API/ExRate_API.dll"]
EXPOSE 80

API调用Python脚本的C#代码

public string getOutputInContainer(string targetCurrency, string baseCurrency)
{
    _logger.LogInformation($"Container method running");

    var scriptPath = "/app/ExRate_Service/Program.py";

    var output = string.Empty;
    var process = new Process
    {
        StartInfo = new ProcessStartInfo
        {
            FileName = "/usr/local/lib/python3.9",
            Arguments = scriptPath + $" -b {targetCurrency} -t {baseCurrency}",
            UseShellExecute = false,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            CreateNoWindow = true
        },
        EnableRaisingEvents = true
    };

    process.ErrorDataReceived += (sender, e) =>
    {
        if (!string.IsNullOrEmpty(e.Data))
        {
            _logger.LogInformation($"Error from process: {e.Data}");
        }
    };
    process.OutputDataReceived += (sender, e) =>
    {
        if (!string.IsNullOrEmpty(e.Data))
        {
            _logger.LogInformation($"Output from process: {e.Data}");
            output += e.Data;
        }
    };

    process.Start();
    process.BeginErrorReadLine();
    process.BeginOutputReadLine();
    process.WaitForExit();

    _logger.LogInformation($"Raw output: {output}");

    var historicalData = JsonConvert.DeserializeObject<Dictionary<string, object>>(output.Substring(0, output.IndexOf("}") + 1));
    var forecast = JsonConvert.DeserializeObject<Dictionary<string, object>>(output.Substring(output.IndexOf("}") + 1));

    _logger.LogInformation($"Forecast: {JsonConvert.SerializeObject(forecast)}");

    var result = new Dictionary<string, Dictionary<string, object>>();
    result.Add("historicalData", historicalData ?? new Dictionary<string, object>());
    result.Add("forecast", forecast ?? new Dictionary<string, object>());

    _logger.LogInformation($"Result: {JsonConvert.SerializeObject(result)}");

    var json = JsonConvert.SerializeObject(result, Formatting.Indented);

    _logger.LogInformation($"Final JSON: {json}");

    return json;
}

运行容器时的错误日志

info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://[::]:80
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /app/
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 GET http://localhost:8080/api/GetExRateForecast/USD&EUR - -
warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
      Failed to determine the https port for redirect.
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint 'ExRate_API.Controllers.GetExRateForecastController.Get (ExRate_API)'
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[3]
      Route matched with {action = "Get", controller = "GetExRateForecast"}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult Get(System.String, System.String) on controller ExRate_API.Controllers.GetExRateForecastController (ExRate_API).
info: ExRate_API.Controllers.GetExRateForecastController[0]
      Request received for baseCurrency: USD, targetCurrency: EUR
info: ExRate_API.Controllers.GetExRateForecastController[0]
      Container method running
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2]
      Executed action ExRate_API.Controllers.GetExRateForecastController.Get (ExRate_API) in 35.3081ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'ExRate_API.Controllers.GetExRateForecastController.Get (ExRate_API)'
fail: Microsoft.AspNetCore.Server.Kestrel[13]
      Connection id "0HMOTGC8R42M3", Request id "0HMOTGC8R42M3:00000002": An unhandled exception was thrown by the application.
      System.ComponentModel.Win32Exception (0x80004005): The FileName property should not be a directory unless UseShellExecute is set.         at System.Diagnostics.Process.StartCore(ProcessStartInfo startInfo)
         at System.Diagnostics.Process.Start()
         at ExRate_API.DataFromService.GetExRateForecast.getOutputInContainer(String targetCurrency, String baseCurrency) in /app/ExRate_API/DataFromService/GetExRateForecast.cs:line 97
         at ExRate_API.Controllers.GetExRateForecastController.Get(String baseCurrency, String targetCurrency) in /app/ExRate_API/Controllers/GetExRateForecastController.cs:line 30
         at lambda_method2(Closure , Object , Object[] )
         at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
      --- End of stack trace from previous location ---
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
      --- End of stack trace from previous location ---
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
         at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
         at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 GET http://localhost:8080/api/GetExRateForecast/USD&EUR - - - 500 0 - 155.0379ms

用户疑问

进入容器bash控制台后,能看到python3及所有依赖均已安装,但脚本无法找到numpy(假设最先失败的是它)或其他依赖,恳请提供帮助或指导。


解决方案

1. 修复Python可执行文件路径错误

错误日志明确提示:The FileName property should not be a directory unless UseShellExecute is set,这是因为你在ProcessStartInfo里把FileName设成了Python的目录/usr/local/lib/python3.9,而非可执行文件路径。

正确的Python可执行文件路径应为/usr/local/bin/python3或/usr/local/bin/python,修改C#代码中的FileName:

FileName = "/usr/local/bin/python3",

2. 确保Python依赖路径正确

虽然复制了site-packages目录,但可能存在路径权限或Python环境变量问题。可在Dockerfile的final阶段添加环境变量,明确Python模块路径:

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS final
WORKDIR /app
ENV PYTHONPATH="/usr/local/lib/python3.9/site-packages"
COPY --from=build /app ExRate_Service
COPY --from=build /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages
COPY --from=package /app/out ExRate_API
ENTRYPOINT ["dotnet", "ExRate_API/ExRate_API.dll"]
EXPOSE 80

3. 验证Python环境是否正常

可在Dockerfile的final阶段添加验证命令,确保Python和依赖能正常加载:

RUN python3 -c "import numpy; print('Numpy imported successfully')"

如果构建时出错,说明依赖复制过程有问题,需检查site-packages的复制是否完整。

4. 优化Docker镜像构建(可选)

为避免手动复制site-packages可能带来的问题,可在多阶段构建时直接复制Python环境的完整目录,或使用pip install到指定目录再复制:

FROM python:3.9.10-slim-buster AS build
WORKDIR /app
RUN pip install --target=/python-packages numpy pandas requests python-dotenv tensorflow scikit-learn keras matplotlib
COPY ./ExRate_Service .
# ... 其他阶段 ...
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS final
WORKDIR /app
ENV PYTHONPATH="/python-packages"
COPY --from=build /python-packages /python-packages
COPY --from=build /app ExRate_Service
# ... 其他复制步骤 ...

内容的提问来源于stack exchange,提问作者David Beesley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 02:42:10