2010-03-02 18 views
13

मुझे क्लाइंट साइड एक्सएएमएल (सिल्वरलाइट से) लेने और सर्वर साइड रिसोर्सेज (हाई रेज इमेज) के साथ विलय करने की आवश्यकता है और WPF (DrawingContext आदि) का उपयोग करके इसे आसानी से कर सकते हैं। यह उल्लेख किया गया है कि सर्वर पक्ष (आईआईएस डब्ल्यूसीएफ में होस्ट किया गया) डब्ल्यूपीएफ का उपयोग सर्वर पर कार्यालय चलाने और वास्तव में एक बुरा विचार है।डब्ल्यूपीएफ एपीआई को डब्ल्यूसीएफ सेवा में सुरक्षित रूप से इस्तेमाल किया जा सकता है?

क्या डब्ल्यूपीएफ सर्वर पर चलाने के लिए बनाया गया है? विकल्प क्या हैं (विशेष रूप से xaml के साथ)? मुझे (मेमोरी लीक, थ्रेडिंग इत्यादि) देखने के लिए क्या चाहिए?

+3

का उपयोग करने के लिए नीचे दिए गए कोड का उपयोग करें। –

+1

यह प्रश्न वास्तविक है और इसे व्यक्तिपरक और तर्कवादी के रूप में बंद नहीं किया जाना चाहिए। –

उत्तर

7

डब्ल्यूसीएफ के पीछे डब्ल्यूपीएफ सर्वर-पक्ष का उपयोग Office सर्वर-पक्ष चलाने के बराबर नहीं है! पूरी तरह से डब्ल्यूपीएफ कुछ डीएलएल है, और वास्तव में किसी अन्य पुस्तकालय सर्वर-पक्ष का उपयोग करने से अलग नहीं है। यह वर्ड या एक्सेल, जहां यूजर इंटरफेस सहित दृश्य, पीछे एक पूरा आवेदन लोड कर रहे हैं, ऐड-इन्स, पटकथा भाषा, आदि से पूरी तरह से अलग है

मैं के लिए WCF पीछे सर्वर पर WPF उपयोग किया गया है वर्षों। यह एक बहुत ही सुंदर और कुशल समाधान है:

  • DirectX सॉफ़्टवेयर रेंडरिंग क्योंकि आप एक वास्तविक प्रदर्शन उपकरण में भरते नहीं कर रहे हैं प्रयोग किया जाता है, लेकिन सॉफ्टवेयर DirectX में दिनचर्या प्रतिपादन अत्यधिक अनुकूलित किया गया है तो अपने प्रदर्शन और संसाधनों की खपत है आपके द्वारा प्राप्त किए जा सकने वाले किसी भी प्रतिपादन समाधान के रूप में उतना अच्छा होगा, और शायद बेहतर होगा।

  • डब्ल्यूपीएफ की व्यक्तित्व जटिल ग्राफिक्स को हाथ से करने के बजाय अनुकूलित डायरेक्टएक्स कोड का उपयोग करके बनाई जा सकती है।

व्यावहारिक रूप से बोलते हुए, डब्ल्यूपीएफ सेवा के भीतर से डब्ल्यूपीएफ का उपयोग करके आपके रैम पदचिह्न में लगभग 10 एमबी जोड़ दिया जाएगा।

मुझे WPF सर्वर-पक्ष चलाने के साथ कोई स्मृति रिसाव समस्या नहीं है। मैं XAMLReader का उपयोग ऑब्जेक्ट पेड़ में XAML को पार्स करने के लिए भी कर रहा हूं और पाया है कि जब मैं ऑब्जेक्ट पेड़ का संदर्भ देना बंद करता हूं तो कचरा कलेक्टर इसे बिना किसी समस्या के एकत्र करता है। मुझे हमेशा लगा कि अगर मैं डब्ल्यूपीएफ में मेमोरी लीक में चला गया तो मैं एक अलग ऐपडोमेन में दौड़कर इसके आसपास काम करता हूं जिसे आप कभी-कभी रीसायकल करेंगे, लेकिन मुझे वास्तव में कभी सामना नहीं हुआ।

आपको एक थ्रेडिंग समस्या का सामना करना पड़ेगा कि डब्ल्यूपीएफ को एसटीए धागे की आवश्यकता होती है और डब्ल्यूसीएफ एमटीए धागे का उपयोग करता है। यह एक महत्वपूर्ण समस्या नहीं है क्योंकि आप एमटीए धागे से वही प्रदर्शन प्राप्त करने के लिए एसटीए धागे का पूल प्राप्त कर सकते हैं। मैंने एक छोटी 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; 
    } 
} 
+0

यदि डब्ल्यूपीएफ एप्लिकेशन एक उच्च अंत ग्राफिक्स कार्ड वाले सर्वर पर चल रहा है या बेहतर है, तो उनमें से कुछ, क्या किसी विशिष्ट कार्ड का उपयोग करके इसे प्रस्तुत करने के लिए मजबूर करने का कोई तरीका है? –

+0

मुझे किसी GPU पर इमेजिंग गणनाओं के ऑफ़लोडिंग को मजबूर करने के किसी भी तरीके से नहीं पता है।यह स्वचालित रूप से तब होता है जब सर्वर अनुप्रयोग डेस्कटॉप पर चल रहा है जो वास्तव में भौतिक प्रदर्शन से जुड़ा हुआ है। यह स्वचालित रूप से अन्य समय पर भी हो सकता है। –

+0

@ रेबर्न - मैं एक एचटीपी हैंडलर में जेपीजी खींचने के लिए डब्ल्यूपीएफ का उपयोग करने की कोशिश कर रहा हूं, जैसे वॉटरमार्क प्रकार की चीज़। मुझे एसटीए त्रुटि मिल रही है, लेकिन मुझे पूरा यकीन नहीं है कि इसे ठीक करने के लिए अपने समाधान का उपयोग कैसे करें। अगर मैं एक अलग धागे पर अपना काम करता हूं, तो क्या मेरा एचटीपी हैंडलर खत्म होने से पहले वापस नहीं आएगा? – xr280xr

3

क्या rayburns यहां कहा पर विस्तार हो रहा है कि कैसे मैं STAthread, WPF और Asp.net WebAPI उपयोग कर रहा हूँ। मैंने समानांतर एक्सटेंशन का उपयोग किया, विशेष रूप से नीचे यह फ़ाइल।

//-------------------------------------------------------------------------- 
// 
// Copyright (c) Microsoft Corporation. All rights reserved. 
// 
// File: StaTaskScheduler.cs 
// 
//-------------------------------------------------------------------------- 

using System.Collections.Concurrent; 
using System.Collections.Generic; 
using System.Linq; 

namespace System.Threading.Tasks.Schedulers 
{ 
    public static class ParallelExtensions 
    { 
     public static Task StartNew(this TaskFactory factory, Action action, TaskScheduler scheduler) 
     { 
      return factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, scheduler); 
     } 

     public static Task<TResult> StartNew<TResult>(this TaskFactory factory, Func<TResult> action, TaskScheduler scheduler) 
     { 
      return factory.StartNew<TResult>(action, CancellationToken.None, TaskCreationOptions.None, scheduler); 
     } 

     public static Task<TResult> StartNewSta<TResult>(this TaskFactory factory, Func<TResult> action) 
     { 
      return factory.StartNew<TResult>(action, sharedScheduler); 
     } 

     private static TaskScheduler sharedScheduler = new StaTaskScheduler(1); 
    } 

    /// <summary>Provides a scheduler that uses STA threads.</summary> 
    public sealed class StaTaskScheduler : TaskScheduler, IDisposable 
    { 
     /// <summary>Stores the queued tasks to be executed by our pool of STA threads.</summary> 
     private BlockingCollection<Task> _tasks; 
     /// <summary>The STA threads used by the scheduler.</summary> 
     private readonly List<Thread> _threads; 

     /// <summary>Initializes a new instance of the StaTaskScheduler class with the specified concurrency level.</summary> 
     /// <param name="numberOfThreads">The number of threads that should be created and used by this scheduler.</param> 
     public StaTaskScheduler(int numberOfThreads) 
     { 
      // Validate arguments 
      if (numberOfThreads < 1) throw new ArgumentOutOfRangeException("concurrencyLevel"); 

      // Initialize the tasks collection 
      _tasks = new BlockingCollection<Task>(); 

      // Create the threads to be used by this scheduler 
      _threads = Enumerable.Range(0, numberOfThreads).Select(i => 
      { 
       var thread = new Thread(() => 
       { 
        // Continually get the next task and try to execute it. 
        // This will continue until the scheduler is disposed and no more tasks remain. 
        foreach (var t in _tasks.GetConsumingEnumerable()) 
        { 
         TryExecuteTask(t); 
        } 
       }); 
       thread.IsBackground = true; 
       thread.SetApartmentState(ApartmentState.STA); 
       return thread; 
      }).ToList(); 

      // Start all of the threads 
      _threads.ForEach(t => t.Start()); 
     } 

     /// <summary>Queues a Task to be executed by this scheduler.</summary> 
     /// <param name="task">The task to be executed.</param> 
     protected override void QueueTask(Task task) 
     { 
      // Push it into the blocking collection of tasks 
      _tasks.Add(task); 
     } 

     /// <summary>Provides a list of the scheduled tasks for the debugger to consume.</summary> 
     /// <returns>An enumerable of all tasks currently scheduled.</returns> 
     protected override IEnumerable<Task> GetScheduledTasks() 
     { 
      // Serialize the contents of the blocking collection of tasks for the debugger 
      return _tasks.ToArray(); 
     } 

     /// <summary>Determines whether a Task may be inlined.</summary> 
     /// <param name="task">The task to be executed.</param> 
     /// <param name="taskWasPreviouslyQueued">Whether the task was previously queued.</param> 
     /// <returns>true if the task was successfully inlined; otherwise, false.</returns> 
     protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) 
     { 
      // Try to inline if the current thread is STA 

      return 
       Thread.CurrentThread.GetApartmentState() == ApartmentState.STA && 
       TryExecuteTask(task); 
     } 

     /// <summary>Gets the maximum concurrency level supported by this scheduler.</summary> 
     public override int MaximumConcurrencyLevel 
     { 
      get { return _threads.Count; } 
     } 

     /// <summary> 
     /// Cleans up the scheduler by indicating that no more tasks will be queued. 
     /// This method blocks until all threads successfully shutdown. 
     /// </summary> 
     public void Dispose() 
     { 
      if (_tasks != null) 
      { 
       // Indicate that no new tasks will be coming in 
       _tasks.CompleteAdding(); 

       // Wait for all threads to finish processing tasks 
       foreach (var thread in _threads) thread.Join(); 

       // Cleanup 
       _tasks.Dispose(); 
       _tasks = null; 
      } 
     } 
    } 
} 

उपयोग बहुत आसान है। एक्सटेंशन

Task<MemoryStream> Task1 = Task.Factory.StartNewSta(() => 
      { 

       /* use wpf here*/ 

       BitmapEncoder PngEncoder = 
        new PngBitmapEncoder(); 
       PngEncoder.Frames.Add(BitmapFrame.Create(Render)); 

       //save to memory stream 
       var Ms = new MemoryStream(); 

       PngEncoder.Save(Ms);     
       return Ms; 
      }); 
    Task.WaitAll(Task1); 

    return Task1.Result; 
संबंधित मुद्दे

 संबंधित मुद्दे