【问题标题】:Invoke or call C# console app from C# web service?从 C# Web 服务调用或调用 C# 控制台应用程序?
【发布时间】:2011-10-29 03:37:50
【问题描述】:

由于我的问题,我无法通过我的网络服务运行 dos 命令。

C# web service running batch file or dos command?

由于我不能让我的 web 服务直接运行 dos 命令,我现在正在考虑创建一个将运行我的 dos 命令的 C# 控制台应用程序,然后该控制台应用程序将被 web 服务调用。

可以吗?

【问题讨论】:

  • 您可以从您的 Web 服务器执行控制台应用程序,但您所做的只是将代码从您的 Web 服务转移到控制台应用程序中。存在的任何限制仍然存在。
  • 我不确定你的架构。您是指 Web 服务通过 SOAP 还是网络协议调用您的应用程序?
  • 我勾选了“允许服务与桌面交互”,但没有任何反应... T_T

标签: c# asp.net web-services console-application


【解决方案1】:

如果可以从 Web 服务中实现,您需要执行以下两项操作之一:

  • 使用模拟来执行控制台应用程序
  • 在 IIS 中使用可以执行应用程序的帐户。

假设上述其中一项工作正常并且您能够执行控制台应用程序,那么您还需要研究一些其他事项:

  • 您可能需要在 IIS 的主目录选项卡下更改执行权限
  • 您可能需要取消控制台对话框,因为这可能会引发一些标志

我以前必须这样做一次,而标准模拟对我不起作用。我不得不以不同的方式处理模仿。我不知道你是否会遇到和我一样的障碍,但这是我创建的一个类,用于通过 Windows API 以编程方式模拟:

编辑

更改为实现 IDisposable 的实例类 - 感谢@John Saunders

添加了一个重载的构造函数,以便于使用 using 语句实现,并添加了布尔属性 Impersonating 以检查实例当前是否正在模拟。还有 BeginImpersonationContext 和 EndImpersonationContext 方法可供替代使用。

/// <summary>
/// Leverages the Windows API (advapi32.dll) to programmatically impersonate a user.
/// </summary>
public class ImpersonationContext : IDisposable
{
    #region constants

    private const int LOGON32_LOGON_INTERACTIVE = 2;
    private const int LOGON32_PROVIDER_DEFAULT = 0;

    #endregion

    #region global variables

    private WindowsImpersonationContext impersonationContext;
    private bool impersonating;

    #endregion

    #region unmanaged code

    [DllImport("advapi32.dll")]
    private static extern int LogonUserA(String lpszUserName, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool RevertToSelf();

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    private static extern bool CloseHandle(IntPtr handle);

    #endregion

    #region constructors

    public ImpersonationContext()
    {
        impersonating = false;
    }

    /// <summary>
    /// Overloaded constructor and begins impersonating.
    /// </summary>
    public ImpersonationContext(string userName, string password, string domain)
    {
        this.BeginImpersonationContext(userName, password, domain);
    }

    #endregion

    #region impersonation methods

    /// <summary>
    /// Begins the impersonation context for the specified user.
    /// </summary>
    /// <remarks>Don't call this method if you used the overloaded constructor.</remarks>
    public void BeginImpersonationContext(string userName, string password, string domain)
    {
        //initialize token and duplicate variables
        IntPtr token = IntPtr.Zero;
        IntPtr tokenDuplicate = IntPtr.Zero;

        if (RevertToSelf())
        {
            if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) != 0)
            {
                if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                {
                    using (WindowsIdentity tempWindowsIdentity = new WindowsIdentity(tokenDuplicate))
                    {
                        //begin the impersonation context and mark impersonating true
                        impersonationContext = tempWindowsIdentity.Impersonate();
                        impersonating = true;
                    }
                }
            }
        }

        //close the handle to the account token
        if (token != IntPtr.Zero)
            CloseHandle(token);

        //close the handle to the duplicated account token
        if (tokenDuplicate != IntPtr.Zero)
            CloseHandle(tokenDuplicate);
    }

    /// <summary>
    /// Ends the current impersonation context.
    /// </summary>
    public void EndImpersonationContext()
    {
        //if the context exists undo it and dispose of the object
        if (impersonationContext != null)
        {
            //end the impersonation context and dispose of the object
            impersonationContext.Undo();
            impersonationContext.Dispose();
        }

        //mark the impersonation flag false
        impersonating = false;
    }

    #endregion

    #region properties

    /// <summary>
    /// Gets a value indicating whether the impersonation is currently active.
    /// </summary>
    public bool Impersonating
    {
        get
        {
            return impersonating;
        }
    }

    #endregion

    #region IDisposable implementation

    ~ImpersonationContext()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);               
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (impersonationContext != null)
            {
                impersonationContext.Undo();
                impersonationContext.Dispose();
            }
        }
    }

    #endregion    
}

编辑

最后,这里是一个如何实现类的例子:

using (ImpersonationContext context = new ImpersonationContext("user", "password", "domain"))
{
    if (context.Impersonating)
    {
        Process.Start(@"/Support/SendFax/SendFax.exe");
    }
}

【讨论】:

  • 非常感谢詹姆斯!但我还有一个我真的不知道的愚蠢问题。你能告诉我如何在我的网络服务中启动这个控制台应用程序吗? (我的意思是它可以由 xxx.start(console app) 调用,或者它可以作为项目参考或其他东西添加?)
  • 看起来不错的类,但也许它应该是一个实例类并实现 IDisposable?
  • Process.Start 将运行控制台应用程序。如果这是您所要求的,您将无法看到控制台,因为它将在服务器的幕后运行。
  • 好的,我想我找到了解决方案,使用 server.mappath(app);再次感谢您!我会尽快尝试!
  • @NandNand:我认为模拟可能也可以解决您在上一个问题中遇到的问题。在您使此解决方案正常工作后,您可能希望尝试将控制台应用程序的代码直接放在您的 Web 服务中,并将此模拟添加到该代码中。如果可行,您可以完全摆脱控制台应用程序,并将此功能保留在您的 Web 服务中。
【解决方案2】:

从另一个 .Net 应用程序调用 .Net 控制台应用程序的最简单方法是在程序集中进行链接,然后直接调用静态 Main 方法。但是如果有任何原因你不能执行命令(权限),那么你会遇到同样的问题。

如果权限是问题,那么您可以:

  • 更改 ASP.Net 用于托管您的 Web 服务的帐户
  • 创建一个承载 WCF 或 .Net Remoting 侦听器的 Windows 服务。设计侦听器以生成您需要运行的进程。使用您需要的权限运行该服务

此外,正如 John Kalberer 所提到的,这可能与这些服务无法与桌面交互有关。如果这是问题所在,then see this question

【讨论】:

  • 更改 ASP.Net 用于托管您的 Web 服务的帐户 - 您能告诉我该怎么做吗?
  • 我有兴趣创建一个 Windows 服务并从我的 Web 服务中调用它。有可能吗?如何从 Web 服务调用 Windows 服务。 (对不起,如果我问的太多。我对 .NET 很陌生。)
  • @NandNand:您可以在 IIS 中更改网站的权限 - inetmgr.exe。 MSDN 上还有 WCF 和 .Net 远程处理的示例。我会阅读这些示例并按照其中的说明进行操作。 Windows 服务将是您的服务主机,而您现有的 Web 服务将是一个服务客户端。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-25
  • 1970-01-01
  • 2013-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多