Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 324895
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 12, 20262026-05-12T09:09:58+00:00 2026-05-12T09:09:58+00:00

Everything I’m told says that WCF should be at least as fast as remoting.

  • 0

Everything I’m told says that WCF should be at least as fast as remoting. I have a specific scenario here, however, where it isn’t even close, and I’m wondering if someone can spot something obvious that I’m doing wrong. I’m looking into the possibility of replacing remoting with wcf for the in-process intra-appdomain communication heavy lifting. Here’s the code:

[ServiceContract]
interface IWorkerObject
{
    [OperationContract] Outcome DoWork(Input t);
}

[DataContract]
[Serializable]
class Input
{
    [DataMember] public int TaskId { get; set; }
    [DataMember] public int ParentTaskId { get; set; }
    [DataMember] public DateTime DateCreated { get; set; }
    [DataMember] public string TextData { get; set; }
    [DataMember] public byte[] BinaryData { get; set; }
}

[DataContract]
[Serializable]
class Outcome
{
    [DataMember] public string Result { get; set; }
    [DataMember] public string TextData { get; set; }
    [DataMember] public byte[] BinaryData { get; set; }

}

class Program
{
    static void Main(string[] args)
    {
        run_rem_test();
        run_wcf_test();
        run_rem_test();
        run_wcf_test();
    }

    static void run_rem_test()
    {
        var dom = AppDomain.CreateDomain("remoting domain", null);
        var obj = dom.CreateInstanceFromAndUnwrap(System.Reflection.Assembly.GetExecutingAssembly().Location, typeof(WorkerObject).FullName) as IWorkerObject;

        RunTest("remoting", obj);

        AppDomain.Unload(dom);
    }

    static void run_wcf_test()
    {
        var dom  = AppDomain.CreateDomain("wcf domain", null);
        var dcnt = dom.CreateInstanceFromAndUnwrap(System.Reflection.Assembly.GetExecutingAssembly().Location, typeof(WorkerObject).FullName) as WorkerObject;
        var fact = new ChannelFactory<IWorkerObject>(new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "net.pipe://localhost/the_channel");
        var chan = fact.CreateChannel();

        dcnt.OpenChannel();

        RunTest("wcf", chan);

        fact.Close();

        dcnt.CloseChannel();

        AppDomain.Unload(dom);
    }

    static void RunTest(string test, IWorkerObject dom)
    {
        var t = new Input()
        {
            TextData     = new string('a', 8192),
            BinaryData   = null,
            DateCreated  = DateTime.Now,
            TaskId       = 12345,
            ParentTaskId = 12344,
        };

        var sw = System.Diagnostics.Stopwatch.StartNew();

        for( var i = 0; i < 1000; i++ )
            dom.DoWork(t);

        sw.Stop();

        Console.WriteLine("{1} test run in {0}ms", sw.ElapsedMilliseconds, test);
    }

}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class WorkerObject : MarshalByRefObject, IWorkerObject
{
    ServiceHost m_host;

    public void OpenChannel()
    {
        m_host = new ServiceHost(this);

        m_host.AddServiceEndpoint(typeof(IWorkerObject), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "net.pipe://localhost/the_channel");

        m_host.Open();
    }

    public void CloseChannel()
    {
        m_host.Close();
    }

    public Outcome DoWork(Input t)
    {
        return new Outcome()
        {
            TextData   = new string('b', 8192),
            BinaryData = new byte[1024],
            Result     = "the result",
        };
    }

}

When I run this code I get numbers that look like this:

remoting test run in 386ms
wcf test run in 3467ms
remoting test run in 499ms
wcf test run in 1840ms

UPDATE: So it turns out that it’s just the initial setup that is so costly for WCF (Thanks, Zach!). Because I was recreating the AppDomains in each test, I was paying that price over and over. Here’s the updated code:

[ServiceContract]
interface IWorkerObject
{
    [OperationContract] Outcome DoWork(Input t);
}

[DataContract]
[Serializable]
class Input
{
    [DataMember] public int TaskId { get; set; }
    [DataMember] public int ParentTaskId { get; set; }
    [DataMember] public DateTime DateCreated { get; set; }
    [DataMember] public string TextData { get; set; }
    [DataMember] public byte[] BinaryData { get; set; }
}

[DataContract]
[Serializable]
class Outcome
{
    [DataMember] public string Result { get; set; }
    [DataMember] public string TextData { get; set; }
    [DataMember] public byte[] BinaryData { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var rem_dom = AppDomain.CreateDomain("remoting domain", null);
        var rem_obj = rem_dom.CreateInstanceFromAndUnwrap(System.Reflection.Assembly.GetExecutingAssembly().Location, typeof(WorkerObject).FullName) as IWorkerObject;

        var wcf_dom = AppDomain.CreateDomain("wcf domain", null);
        var mgr_obj = wcf_dom.CreateInstanceFromAndUnwrap(System.Reflection.Assembly.GetExecutingAssembly().Location, typeof(WorkerObject).FullName) as WorkerObject;
        var fact    = new ChannelFactory<IWorkerObject>(new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "net.pipe://localhost/the_channel");
        var wcf_obj = fact.CreateChannel();

        var rem_tot = 0L;
        var wcf_tot = 0L;

        mgr_obj.OpenChannel();

        for( var i = 0; i < 10; i++ )
        {
            rem_tot += RunTest("remoting", i, rem_obj);
            wcf_tot += RunTest("wcf",      i, wcf_obj);
        }

        fact.Close();

        mgr_obj.CloseChannel();

        AppDomain.Unload(rem_dom);
        AppDomain.Unload(wcf_dom);

        Console.WriteLine();
        Console.WriteLine("remoting total: {0}", rem_tot);
        Console.WriteLine("wcf total:      {0}", wcf_tot);
    }

    static long RunTest(string test, int iter, IWorkerObject dom)
    {
        var t = new Input()
        {
            TextData     = new string('a', 8192),
            BinaryData   = null,
            DateCreated  = DateTime.Now,
            TaskId       = 12345,
            ParentTaskId = 12344,
        };

        var sw = System.Diagnostics.Stopwatch.StartNew();

        for( var i = 0; i < 1000; i++ )
            dom.DoWork(t);

        sw.Stop();

        Console.WriteLine("{1,-8} {2,2} test run in {0}ms", sw.ElapsedMilliseconds, test, iter);

        return sw.ElapsedMilliseconds;
    }

}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class WorkerObject : MarshalByRefObject, IWorkerObject
{
    ServiceHost m_host;

    public void OpenChannel()
    {
        m_host = new ServiceHost(typeof(WorkerObject));

        m_host.AddServiceEndpoint(typeof(IWorkerObject), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "net.pipe://localhost/the_channel");

        m_host.Open();
    }

    public void CloseChannel()
    {
        m_host.Close();
    }

    public Outcome DoWork(Input t)
    {
        return new Outcome()
        {
            TextData   = new string('b', 8192),
            BinaryData = new byte[1024],
            Result     = "the result",
        };
    }

}

This code gives numbers like this:

remoting  0 test run in 377ms
wcf       0 test run in 2255ms
remoting  1 test run in 488ms
wcf       1 test run in 353ms
remoting  2 test run in 507ms
wcf       2 test run in 355ms
remoting  3 test run in 495ms
wcf       3 test run in 351ms
remoting  4 test run in 484ms
wcf       4 test run in 344ms
remoting  5 test run in 484ms
wcf       5 test run in 354ms
remoting  6 test run in 483ms
wcf       6 test run in 346ms
remoting  7 test run in 491ms
wcf       7 test run in 347ms
remoting  8 test run in 485ms
wcf       8 test run in 358ms
remoting  9 test run in 494ms
wcf       9 test run in 338ms

remoting total: 4788
wcf total:      5401
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-12T09:09:59+00:00Added an answer on May 12, 2026 at 9:09 am

    The Notes

    For the most part, the time is spent setting up and tearing down the WCF channel. The other lions share of time appears to be consumed by running within a debugger. Keep in mind this is really informal type testing.. 🙂

    I was able to reproduce your numbers, so i started from there. This showed WCF numbers were roughly 3xs greater than the remoting numbers.

    By caching the channel factory (and respective remoting objects), the numbers dropped so that WCF was only 2x’s greater than the remoting numbers.

    After trying a dozen other different tweaks, the only one that seemed to shave any real measurable time off the numbers was to clear all the debug service behaviors (added by default) – this resulted in roughly ~100ms. Not enough to really get excited about.

    Then, on a whim, I ran the code outside the debugger, in a release configuration. The numbers dropped to roughly the equivalent of the remoting numbers, if not better. Forehead smacked the desk and called it done.

    In a nutshell, you should see roughly the same, with a possibility of better performance using WCF and gain a better programming model to boot.

    Sample Run

    remoting 1 test run in 347ms    
    wcf      1 test run in 1544ms    
    remoting 2 test run in 493ms    
    wcf      2 test run in 324ms
    remoting 3 test run in 497ms
    wcf      3 test run in 336ms
    remoting 4 test run in 449ms
    wcf      4 test run in 289ms
    remoting 5 test run in 448ms
    wcf      5 test run in 284ms
    remoting 6 test run in 447ms
    wcf      6 test run in 282ms
    remoting 7 test run in 439ms
    wcf      7 test run in 281ms
    remoting 8 test run in 441ms
    wcf      8 test run in 278ms
    remoting 9 test run in 441ms
    wcf      9 test run in 278ms
    remoting 10 test run in 438ms
    wcf      10 test run in 286ms
    

    The Code

    Note – this code has been completely bastardized. I apologize. 🙂

    using System;
    using System.ServiceModel;
    using System.Runtime.Serialization;
    
    
    
    [ServiceContract]
    interface IWorkerObject
    {
        [OperationContract]
        Outcome DoWork(Input t);
    }
    
    [DataContract]
    [Serializable]
    class Input
    {
        [DataMember]
        public int TaskId { get; set; }
        [DataMember]
        public int ParentTaskId { get; set; }
        [DataMember]
        public DateTime DateCreated { get; set; }
        [DataMember]
        public string TextData { get; set; }
        [DataMember]
        public byte[] BinaryData { get; set; }
    }
    
    [DataContract]
    [Serializable]
    class Outcome
    {
        [DataMember]
        public string Result { get; set; }
        [DataMember]
        public string TextData { get; set; }
        [DataMember]
        public byte[] BinaryData { get; set; }
    
    }
    
    class Program
    {
        static AppDomain dom = AppDomain.CreateDomain("wcf domain", null);
        static WorkerObject dcnt = dom.CreateInstanceFromAndUnwrap(System.Reflection.Assembly.GetExecutingAssembly().Location, typeof(WorkerObject).FullName) as WorkerObject;
        static ChannelFactory<IWorkerObject> fact = new ChannelFactory<IWorkerObject>(new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "net.pipe://localhost/the_channel");
        static IWorkerObject chan = fact.CreateChannel();
        static AppDomain remdom = AppDomain.CreateDomain("remoting domain", null);
        static IWorkerObject remoteObject;
    
        static void Main(string[] args)
        {
    
            remoteObject = remdom.CreateInstanceFromAndUnwrap(System.Reflection.Assembly.GetExecutingAssembly().Location, typeof(WorkerObject).FullName) as IWorkerObject;
    
    
            dcnt.OpenChannel();
    
    
            int numberOfIterations = 10;
    
            for (int i = 1; i <= numberOfIterations; i++)
            {
                run_rem_test(i);
                run_wcf_test(i);
            }
    
            fact.Close();
    
            dcnt.CloseChannel();
    
            AppDomain.Unload(dom);
            AppDomain.Unload(remdom);
    
    
    
        }
    
        static void run_rem_test(int iteration)
        {
    
            RunTest("remoting " + iteration, remoteObject);
    
    
        }
    
        static void run_wcf_test(int iteration)
        {
    
    
            RunTest("wcf      " + iteration, chan);
    
        }
    
        static void RunTest(string test, IWorkerObject dom)
        {
            var t = new Input()
            {
                TextData = new string('a', 8192),
                BinaryData = null,
                DateCreated = DateTime.Now,
                TaskId = 12345,
                ParentTaskId = 12344,
            };
    
            var sw = System.Diagnostics.Stopwatch.StartNew();
    
            for (var i = 0; i < 1000; i++)
                dom.DoWork(t);
    
            sw.Stop();
    
            Console.WriteLine("{1} test run in {0}ms", sw.ElapsedMilliseconds, test);
        }
    
    }
    
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    class WorkerObject : MarshalByRefObject, IWorkerObject
    {
        ServiceHost m_host;
    
        public void OpenChannel()
        {
            m_host = new ServiceHost(typeof(WorkerObject));
    
    
            m_host.AddServiceEndpoint(typeof(IWorkerObject), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), "net.pipe://localhost/the_channel");
    
            // cache our ServiceBehaviorAttribute, clear all other behaviors (mainly debug)
            // and add our ServiceBehavior back
            //
            var b = m_host.Description.Behaviors[0] as ServiceBehaviorAttribute;
    
    
            m_host.Description.Behaviors.Clear();
    
            m_host.Description.Behaviors.Add(b);
    
    
    
            m_host.Open();
        }
    
        public void CloseChannel()
        {
            m_host.Close();
        }
    
        public Outcome DoWork(Input t)
        {
            return new Outcome()
            {
                TextData = new string('b', 8192),
                BinaryData = new byte[1024],
                Result = "the result",
            };
        }
    
    }
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Everything I am reading about rails 3 and AJAX says that we should have
Everything I have read says that when making a managed stored procedure, to right
Everything you do with XML is case sensitive, I know that. However, right now
Everything is working up to here, I just need to create the method that
Everything I read about cookies says that setting the expiry time of a cookie
Everything I know about .Net programming tells me that the behavior I see here
Everything that isn't labeled calc or finalvalue is raw data that I will be
Everything i read tells me this should work page 1 is <?php $state =
Everything below works fine, except that the form doesnt get submitted... it seems the
Everything is in the title, I want to be able to delete account that

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.