c# - WPF API 能否在 WCF 服务中安全使用?

标签 c# wpf wcf xaml image-processing

我需要采用客户端 XAML(来自 Silverlight)并创建一个与服务器端资源(高分辨率图像)合并的位图,并且可以使用 WPF(DrawingContext 等)轻松完成此操作。有人提到服务器端(托管在 IIS WCF 中)使用 WPF 类似于在服务器上运行 Office,这是一个非常糟糕的主意。

WPF 是为在服务器上运行而构建的吗?有哪些替代方案(尤其是使用 xaml)?我需要注意什么(内存泄漏、线程等)?

最佳答案

在 WCF 后面使用 WPF 服务器端等同于在服务器端运行 Office! WPF 作为一个整体只是几个 DLL,实际上与使用任何其他库服务器端没有什么不同。这与 Word 或 Excel完全不同,后者是在后台加载整个应用程序,包括用户界面、加载项、脚本语言等。

多年来,我一直在 WCF 背后的服务器上使用 WPF。这是一个非常优雅和高效的解决方案:

  • 使用 DirectX 软件渲染是因为您不是在实际的显示设备上绘图,但 DirectX 中的软件渲染例程已经过高度优化,因此您的性能和资源消耗将与您使用的任何渲染解决方案一样好可能会找到,而且可能会好得多。

  • WPF 的表现力允许使用优化的 DirectX 代码创建复杂的图形,而不是手动创建。

实际上,在 WCF 服务中使用 WPF 会增加大约 10MB 的 RAM 占用空间。

我在运行 WPF 服务器端时没有遇到任何内存泄漏问题。我还使用 XamlReader 将 XAML 解析为对象树,并且发现当我停止引用对象树时,垃圾收集器可以毫无问题地收集它。我一直认为,如果我确实在 WPF 中遇到内存泄漏,我会通过在您偶尔会回收的单独 AppDomain 中运行来解决它,但我从未真正遇到过。

您将遇到的一个线程问题是 WPF 需要 STA 线程,而 WCF 使用 MTA 线程。这不是一个严重的问题,因为您可以使用一个 STA 线程池来获得与从 MTA 线程获得相同的性能。我写了一个小的 STAThreadPool 类来处理转换。在这里:

// A simple thread pool implementation that provides STA threads instead of the MTA threads provided by the built-in thread pool
public class STAThreadPool
{
  int _maxThreads;
  int _startedThreads;
  int _idleThreads;
  Queue<Action> _workQueue = new Queue<Action>();

  public STAThreadPool(int maxThreads)
  {
    _maxThreads = maxThreads;
  }

  void Run()
  {
    while(true)
      try
      {
        Action action;
        lock(_workQueue)
        {
          _idleThreads++;
          while(_workQueue.Count==0)
            Monitor.Wait(_workQueue);
          action = _workQueue.Dequeue();
          _idleThreads++;
        }
        action();
      }
      catch(Exception ex)
      {
        System.Diagnostics.Trace.Write("STAThreadPool thread threw exception " + ex);
      }
  }

  public void QueueWork(Action action)
  {
    lock(_workQueue)
    {
      if(_startedThreads < _maxThreads && _idleThreads <= _workQueue.Count)
        new Thread(Run) { ApartmentState = ApartmentState.STA, IsBackground = true, Name = "STAThreadPool#" + ++_startedThreads }.Start();
      _workQueue.Enqueue(action);
      Monitor.PulseAll(_workQueue);
    }
  }

  public void InvokeOnPoolThread(Action action)
  {
    Exception exception = null;
    using(ManualResetEvent doneEvent = new ManualResetEvent(false))  // someday:  Recycle these events
    {
      QueueWork(delegate
      {
        try { action(); } catch(Exception ex) { exception = ex; }
        doneEvent.Set();
      });
      doneEvent.WaitOne();
    }
    if(exception!=null)
      throw exception;
  }

  public T InvokeOnPoolThread<T>(Func<T> func)
  {
    T result = default(T);
    InvokeOnPoolThread(delegate
    {
      result = func();
    });
    return result;
  }
}

关于c# - WPF API 能否在 WCF 服务中安全使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2363397/

相关文章:

c# - 从同一进程托管和使用 WCF 服务

c# - wcf 联合安全 token 是 session token 还是可重用的?

c# - 无法在 Unity 中停止协程

c# - 红黑树删除问题C#

c# - UI 不更新 bool 更新

c# - 循环依赖和控制反转 - 如何解决这些问题?

VS2005 中的 C# : Can a device project target both full framework and CF?

c# - 了解 WPF - 在模型或 ViewModel 中存储数据

c# - 通过 XAML 将图像设置为按钮背景

c# - 为什么 WCF 服务作为 PID 4 (SYSTEM) 而不是托管它的进程的 PID 进行监听?