简体   繁体   English

从 C# web 服务调用或调用 C# 控制台应用程序?

[英]Invoke or call C# console app from C# web service?

Due to my problem that I am unable to run dos command via my web service.由于我的问题,我无法通过我的 web 服务运行 dos 命令。

C# web service running batch file or dos command? C# web 服务运行批处理文件或dos命令?

Since I cannot make my web service run dos command directly, I am now thinking about creating C# console app that will run my dos command, then the console app will be invoked by web service.由于我不能让我的 web 服务直接运行 dos 命令,我现在正在考虑创建 C# 控制台应用程序来运行我的 dos 命令,然后控制台应用程序将由 Z2567A5EC9705EB7AC2C984033E0618 调用

Is it possible to do so?有可能这样做吗?

If it's possible from within a web service, you'll need to do one of two things:如果可以从 web 服务中实现,则需要执行以下两项操作之一:

  • Use impersonation to execute the console application使用模拟执行控制台应用程序
  • Use an account in IIS that can execute the application.使用 IIS 中可以执行应用程序的帐户。

Assuming that one of the above works and you're able to execute the console app, there are also a few other things you'll need to look into:假设上述其中一项有效并且您能够执行控制台应用程序,那么您还需要研究其他一些事项:

  • You may need to change the execute permissions under the Home Directory tab in IIS您可能需要在 IIS 的主目录选项卡下更改执行权限
  • You may need to suppress the console dialog, as this may raise some flags您可能需要禁止控制台对话框,因为这可能会引发一些标志

I had to do this once before, and standard impersonation didn't work for me.我以前必须这样做一次,标准模拟对我不起作用。 I had to handle impersonation a little differently.我不得不以不同的方式处理模仿。 I don't know if you'll run into the same obstacles that I did, but here is a class that I created for impersonating programmatically through the Windows API:我不知道您是否会遇到与我相同的障碍,但这是我创建的 class,用于通过 Windows API 以编程方式模拟:

EDIT编辑

Changed to an instance class implementing IDisposable - thanks @John Saunders更改为实现 IDisposable 的实例 class - 感谢@John Saunders

Added an overloaded constructor for easier implementation with using statement, and added boolean property Impersonating to check whether the instance is currently impersonating.添加了一个重载的构造函数以便于使用 using 语句实现,并添加了 boolean 属性 Impersonating 以检查实例当前是否正在模拟。 There are also BeginImpersonationContext and EndImpersonationContext methods for alternative use.还有 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    
}

EDIT编辑

Lastly, here is an example of how to implement the class:最后,这是一个如何实现 class 的示例:

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

The easiest method to call a.Net console application from another.Net application is to link in the assembly, and invoke the static Main method directly.从另一个.Net 应用程序调用一个.Net 控制台应用程序的最简单方法是在程序集中进行链接,然后直接调用 static Main方法。 But if there is any reason you can't execute commands (permissions), then you'll have the same problems with this method.但是,如果有任何原因您无法执行命令(权限),那么您将遇到与此方法相同的问题。

If permissions are the problem, then you could:如果权限是问题,那么您可以:

  • Change the account ASP.Net uses to host your web service更改 ASP.Net 用于托管 web 服务的帐户
  • Create a Windows service that hosts a WCF or.Net Remoting listener.创建托管 WCF 或 .Net Remoting 侦听器的 Windows 服务。 Design the listener to spawn the processes you need to run.设计侦听器以生成您需要运行的进程。 Run that service with the permissions you require使用您需要的权限运行该服务

Also, as John Kalberer mentioned, it could be related to the inability of these services to interact with the desktop.此外,正如 John Kalberer 所提到的,这可能与这些服务无法与桌面交互有关。 If this is the problem, then see this question .如果这是问题, 请参阅此问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM