C# global service runner agent ... thing?



  • Need advice here.

    So I'm writing a C# data import tool for a 3rd party API. The API is implemented as a WCF ServiceReference, generated via WSDL files. All of the 3rd party API's functions return a standard result object.

    This API gets called from like a hundred different places, however I want to create a single centralized function that's in charge of calling it so it can:

    • Implement audit logging (i.e. write literally every request and response to a log file)
    • Take the 3rd party's error messages and transform them into a more digestable form

    Now, the old tool actually has a class called "action", which had the following "helper" method in it:

             //Syntactic sugar to save the user from having to pass type parameters. 
            public static FoobarServiceAction<TResult> Create<TResult>(Expression<Func<IFoobarService, TResult>> operation)
            {
                return new FoobarServiceAction<TResult>(operation);
            }
    

    That doesn't look TOO awful, here's how the action is invoked:

            public OperationResult Execute(IFoobarService foobarService)
            {
                OperationResult = (OperationResult)Operation.Invoke(foobarService, new object[] { Parameter });
                return OperationResult;
            }
    

    And here we run straight into Reflection. It's also ass-backwards code-- instead of creating a Service then executing functions in it, we're creating Actions out of method calls, then calling Action.Execute and passing in the Service. Huh? Confusing as heck.

    There has to be a better way. Is there a better way to wrap a WCF ServiceReference Service in a "handler" that does what I want, but:

    • Doesn't use reflection
    • Can be called in the normal (non-ass-backwards) way?

    Instead of:

    var blah = FoobarAction.Create( scv => svc.AddFoobar(param, param, param) );
    blah.Execute( FoobarService );
    

    I want something like:

    var results = FoobarServiceWrapper.AddFoobar( param, param, param);
    

    Can anybody think of a good way of accomplishing this?



  • Generate wrappers from the reflection data at build-time in case it's a separate assembly? Use a 'dynamic' and forego compile-time checks?



  • @blakeyrat said:

    scv

    ...good to go, sir!"

    Anyway, you just want to wrap the horrible with something that seems more sane, or replace Create and Execute?



  • @Magus said:

    Anyway, you just want to wrap the horrible with something that seems more sane, or replace Create and Execute?

    With what, though?

    I'd really like to not ship a product that relies on reflection to even run, but the more I look into the problem the fewer options I see.

    Unless I can instruct WCF to somehow make wrappers for me as it's importing the WSDL, but that doesn't seem to be possible.

    EDIT: the other option is I write partial classes to extend all 75 of their API endpoints manually. Which suuucks.



  • I'm imagining something more like Service.Add(param, param, param) at the moment, implemented in a rather horrible way...

    I don't know much about your service of course, but it seems like the biggest problem here is determining the types of the parameters, since it sounds like you have a concrete AddFoobar instead of a generic Add thats generic on the interface, with no way of determining the type of the arguments at compile time...

    Am I getting that about right? Just trying to make sure I understand your problem correctly.

    Because you're approaching the point where using t4 to generate wrappers may make more sense than trying to solve this with generics.



  • You will need to wrap the generated methods with your own code with does the logging and error handling. Generics alone won't help you out here, as the methods are different.

    You can try a few things:

    1. T4 text templates to generate a wrapped proxy every time you update your service reference. Tedious, error prone, and nobody likes T4.
    2. Write a PostSharp aspect, which will do the necessary wrapping at compile-time.
    3. Or you could go with Fody to do the same thing.

    It won't be easy (after all, you'll be manipulating IL) but I am pretty sure it will be more fun than writing wrapper methods for each operation in your webservice.



  • Hm. Unless something better comes along by the time I start working on this project again, I'm going to just refactor the existing reflection-using code, and have a frowny-face every time I have to call it.



  • you ought to be able to at the very least use a single method, where the first argument is the service and the second is your previous lambda, except with the type of the first argument, or do it as an extension method to hide the first one. But short of code generation or reflection, you don't really have any options afaik.



  • Hm.

    Well I'm not going to introduce code generation into a solution that's never had it before, so. I guess the "idiot contractors" who created the first version of this tool maybe actually knew a thing or two after all, huh? Heh.

    Using reflection on anything that's not a debugger still really rubs me the wrong way.



  • @blakeyrat said:

    Using reflection on anything that's not a debugger still really rubs me the wrong way.

    It's certainly not ideal. I wouldn't be too worried, though, unless its a well known slow part of your program. Sometimes its the only tool available. If we had macros like lisp, this would be exactly the time to use them.



  • WCF has an "inspector" system you can use to have code run when a request goes out and a response comes in. I'm not sure exactly how much you can see, but I used it recently to log raw response bodies to prove to a vendor that they were generating garbage. There's some framework to set up:

    Create an implementation of IClientMessageInspector. This contains the two functions called when you send a request or receive a response.
    Create an implementation of IEndpointBehavior. In ApplyClientBehavior, add an instance of your IClientMessageInspector implementation to clientRuntime.MessageInspectors.

    You'll have to then add that IEndpointBehavior to your WCF client's Endpoint. If you have a central factory or something where WCF client instances are made, you can just add it to (your client instance).Endpoint.Behaviors.



  • @nexekho's solution's probably the best if you can get it to do what you want. Otherwise, if you want a proxy object, your options are overriding DynamicObject and implementing TryInvoke, which would mean passing around a dynamic everywhere, which would mean no intellisense, implementing FoobarService, which would mean writing shitloads of boilerplate, or depending on something like Castle to do it for you (which is what I'd go with, if it were my decision). It's a pity you're not using Java, which has had dynamic proxies as a language feature since 1.3, back in 2000. By the way, does that reflection you've got there shit itself when the Expression uses named parameters or whatever?



  • I've given it another thought, and I think it actually is possible to do what you want without requiring massive amounts of boilerplate code.

    I have created the following class, representing a mock service:

        public interface IMyService : IDisposable
        {
            int DoubleInput(int input);
            void Trigger();
        }
    
        public class MyService : IMyService
        {
            public MyService()
            {
                Console.WriteLine("Creating service instance");
            }
    
            public int DoubleInput(int input)
            {
                return input * 2;
            }
    
            public void Trigger()
            {
                Console.WriteLine("I are triggered.");
            }
    
            public void Dispose()
            {
                Console.WriteLine("Disposing service");
            }
        }
    

    I have also created the following wrapper class:

        public class ServiceWrapper : IDisposable
        {
            private bool _disposed;
            private readonly IMyService _service;
    
            public ServiceWrapper()
            {
                Console.WriteLine("Creating service wrapper");
                _service = new MyService();
            }
    
            public T Execute<T>(Func<IMyService, T> action)
            {
                try
                {
                    Console.WriteLine("A method is being called");
    
                    if (_disposed)
                        throw new ObjectDisposedException("");
    
                    return action(_service);
                }
                catch (Exception e)
                {
                    Console.WriteLine("An error occured: " + e);
                    throw;
                }
                finally
                {
                    Console.WriteLine("Leaving Execute");
                }
            }
    
            public void Execute(Action<IMyService> action)
            {
                try
                {
                    Console.WriteLine("A method is being called");
    
                    if (_disposed)
                        throw new ObjectDisposedException("");
    
                    action(_service);
                }
                catch (Exception e)
                {
                    Console.WriteLine("An error occured: " + e);
                    throw;
                }
                finally
                {
                    Console.WriteLine("Leaving Execute");
                }
            }
    
            public void Dispose()
            {
                if (!_disposed)
                {
                    _service.Dispose();
                    _disposed = true;
                }
    
                Console.WriteLine("ServiceWrapper is being disposed");
            }
        }
    

    And I finally use it as follows:

        public class Program
        {
            static void Main(string[] args)
            {
                using (var wrapper = new ServiceWrapper())
                {
                    var result = wrapper.Execute(x => x.DoubleInput(24));
                    Console.WriteLine("Service returned: " + result);
                }
    
                Console.WriteLine();
                Console.WriteLine("------------------------------------------");
                Console.WriteLine();
    
                using (var wrapper = new ServiceWrapper())
                {
                    wrapper.Execute(x => x.Trigger());
                    Console.WriteLine("Service returned: nothing");
                }
    
                Console.ReadKey();
            }
        }
    

    Which outputs the following:

    Creating service wrapper
    Creating service instance
    A method is being called
    Leaving Execute
    Service returned: 48
    Disposing service
    ServiceWrapper is being disposed
    
    ------------------------------------------
    
    Creating service wrapper
    Creating service instance
    A method is being called
    I are triggered.
    Leaving Execute
    Service returned: nothing
    Disposing service
    ServiceWrapper is being disposed
    

    It's not exactly what you want (due to the lambda) but it is pretty close to it.

    If you want, you can make this thing generic by exposing the interface as a type parameter and then using a ChannelFactory in the wrapper's constructor to get the actual web service proxy class.



  • @nexekho said:

    WCF has an "inspector" system you can use to have code run when a request goes out and a response comes in. I'm not sure exactly how much you can see, but I used it recently to log raw response bodies to prove to a vendor that they were generating garbage. There's some framework to set up:

    That still sounds like it's designed to support debugging, but it's a better option than reflection so I'll keep it in mind...

    @AlexMedia said:

    I've given it another thought, and I think it actually is possible to do what you want without requiring massive amounts of boilerplate code.

    I have created the following class, representing a mock service:

    Ok I like this solution.


    Now here's a new requirement I forgot to mention because I didn't think of it until this morning on the bus:

    It occurs to me that some of the API calls take the same params. (FoobarRemoveRequest is fed into both CancelFoobar and DeleteFoobar, for an example.) In that case, the audit log, in addition to containing the communication back and forth to the API also needs to contain the API endpoint called--

    Which means I'll probably have to use reflection anyway! Since AFAIK the only way to get that is by asking C# what the name of the WCF ServiceReference method is.



  • @blakeyrat said:

    Now here's a new requirement I forgot to mention because I didn't think of it until this morning on the bus:

    It occurs to me that some of the API calls take the same params. (FoobarRemoveRequest is fed into both CancelFoobar and DeleteFoobar, for an example.) In that case, the audit log, in addition to containing the communication back and forth to the API also needs to contain the API endpoint called--

    Which means I'll probably have to use reflection anyway! Since AFAIK the only way to get that is by asking C# what the name of the WCF ServiceReference method is.

    If you use Expression<Func<IMyservice, T>> you can analyse the expression and determine the method name. Once analysed, you call .Compile() on your expression to evaluate it. This does incur a (small) performance penalty.

    For an example, take a look at http://stackoverflow.com/questions/20420404/how-to-get-method-name-of-generic-funct-passed-into-method



  • Yeah I know. I wish there were a better way, but eh well.



  • If you don't want to mess around with Expressions or reflection, you're down to writing everything by hand I guess. That, or compile time IL weaving.

    Surely that will perform better anyway. :)



  • Performance is a complete non-issue, considering this app will spend 99% of its time waiting for a web service to come back no matter what I do.



  • Then just reflect. You lose typing, but that and the speed are the main reasons its 'bad', so you have more of a reason to use it than most people.



  • Here is the same code as I used before, but then using an Expression to print out the name of the method being called:

        public class ServiceWrapper : IDisposable
        {
            private bool _disposed;
            private readonly IMyService _service;
    
            public ServiceWrapper()
            {
                Console.WriteLine("Creating service wrapper");
                _service = new MyService();
            }
    
            public T Execute<T>(Expression<Func<IMyService, T>> action)
            {
                try
                {
                    Console.WriteLine("A method is being called");
    
                    if (_disposed)
                        throw new ObjectDisposedException("");
    
                    // Grab the name of the method
                    var methodExpression = action.Body as MethodCallExpression;
                    if (methodExpression != null)
                    {
                        Console.WriteLine("Name of called method: {0}", methodExpression.Method.Name);
                    }
    
                    var compiled = action.Compile();
                    return compiled(_service);
                }
                catch (Exception e)
                {
                    Console.WriteLine("An error occured: " + e);
                    throw;
                }
                finally
                {
                    Console.WriteLine("Leaving Execute");
                }
            }
    
            public void Execute(Expression<Action<IMyService>> action)
            {
                try
                {
                    Console.WriteLine("A method is being called");
    
                    if (_disposed)
                        throw new ObjectDisposedException("");
    
                    // Grab the name of the method
                    var methodExpression = action.Body as MethodCallExpression;
                    if (methodExpression != null)
                    {
                        Console.WriteLine("Name of called method: {0}", methodExpression.Method.Name);
                    }
    
                    var compiled = action.Compile();
                    compiled(_service);
                }
                catch (Exception e)
                {
                    Console.WriteLine("An error occured: " + e);
                    throw;
                }
                finally
                {
                    Console.WriteLine("Leaving Execute");
                }
            }
    
            public void Dispose()
            {
                if (!_disposed)
                {
                    _service.Dispose();
                    _disposed = true;
                }
    
                Console.WriteLine("ServiceWrapper is being disposed");
            }
        }
    

    I have not changed any of the other classes. It outputs this:

    Creating service wrapper
    Creating service instance
    A method is being called
    Name of called method: DoubleInput
    Leaving Execute
    Service returned: 48
    Disposing service
    ServiceWrapper is being disposed
    
    ------------------------------------------
    
    Creating service wrapper
    Creating service instance
    A method is being called
    Name of called method: Trigger
    I are triggered.
    Leaving Execute
    Service returned: nothing
    Disposing service
    ServiceWrapper is being disposed
    


  • Thanks, this is super helpful. Ended up spending all day today fighting fires, but I bookmarked this thread for when I (hopefully!) get back on the project on monday.



  • Happy to help! :)


  • Discourse touched me in a no-no place

    @AlexMedia said:

    Once analysed, you call .Compile() on your expression to evaluate it. This does incur a (small) performance penalty.

    If the performance penalty was a problem, you could cache the compiled versions, so you only have to compile each method invocation once. That'd result in a single time overhead the first time you invoke, and then there would be no deficit at all.



  • Ok I'm finally looking into this code.

    Two items:

    1. The WSDL services are actually all static classes, so I removed the IDisposable bits

    2. I want my wrapped version of the service to always return the same object type, something like 3rdPartyAPIResponse. Is there a way to instruct C# that the action is required to return a 3rdPartyAPIResponse, and give me a type-error if it does not? It's not a HUGE deal, all of the 3rdPartyAPIRequests actually do return a 3rdPartyAPIResponse, but it would be nice to do it "correctly" instead of blindly casting a T to the type I need.

    I know I can use where T: blah to constrain types when I'm defining a templated class-- can you do the same in an Action?


    Of course I could just try it and see. Derp.

    Yes, C# lets you set type constraints on methods. So this is valid:

    public MyWrappedAPIResponse Execute<T>(Func<IService, T> action) where T : 3rdPartyAPIResponse
    


  • @blakeyrat said:

    2) I want my wrapped version of the service to always return the same object type, something like 3rdPartyAPIResponse. Is there a way to instruct C# that the action is required to return a 3rdPartyAPIResponse, and give me a type-error if it does not? It's not a HUGE deal, all of the 3rdPartyAPIRequests actually do return a 3rdPartyAPIResponse, but it would be nice to do it "correctly" instead of blindly casting a T to the type I need.

    I know I can use where T: blah to constrain types when I'm defining a templated class-- can you do the same in an Action?

    Yes, you can... but you'll have to get Funcy:

    Just replace this:

    public T Execute<T>(Expression<Func<IMyService, T>> action)
    

    With this:

    public 3rdPartyAPIResponse Execute(Expression<Func<IMyService, 3rdPartyAPIResponse>> action)
    


  • Oh that's an interesting idea too. I could just get rid of the T in the second part of the Func tuple because in my case it's guaranteed to be 3rdPartyAPIResponse... there's not even a point to have a templated return value in this case.

    EDIT: yeah your version builds just fine. I like this better. Thanks!

    EDIT EDIT: Spoke too soon, I seem to have confused the compiler with my magical type wizardry:

    Error 3 The type arguments for method Execute cannot be inferred from the usage. Try specifying the type arguments explicitly.

    EDIT EDIT EDIT: The first version I did with where T: 3rdPartyAPIResponse still works fine, so I'll go with that. It still means I have to cast the T to a 3rdPartyAPIResponse, but at least I know it'll be a "safe" cast.



  • So it specifically cannot be a subtype? Could you seal the class? I don't know.



  • The where T: blah solution is fine; it just means I have to cast T, where I wouldn't if AlexMedia's suggested solution worked. Generally speaking, I don't like to cast T to stuff if I can avoid it, but in this case the compiler'll make sure the cast is "safe" so that's good enough.



  • Quick question: you have a null check on methodExpression != null... is it possible for methodExpression to be null? Is that check necessary?



  • It could, I suppose, be a PropertyExpression. Anyway, again, my point with the previous post was more about why you need the cast in the first place. Maybe you do, I just wanted to know.



  • I need to dig way into the 3rdPartyAPIResponse to find out if the request was successful or not, and then I can implement logging directly in this wrapper class instead of needing to have a logger wrapping a wrapper wrapping a service.



  • Right, but without the cast, you should still have access to all the properties, iirc, because the compiler takes that as "This thing or any subclass".



  • Sigh. New problems. I added the modifications needed to retrieve the methodName.

    var initialTime = DateTime.Now;
    
                    var methodExpression = action.Body as MethodCallExpression;
                    if (methodExpression != null)
                    {
                        Console.WriteLine("Name of called method: {0}", methodExpression.Method.Name);
                    }
    
                    var methodName = methodExpression.Method.Name;
    
                    var compiledAction = action.Compile(service, T);
    
                    var timer = new Stopwatch();
                    timer.Start();
                    var result = compiledAction();
                    timer.Stop();
    

    I think this is correct: the documentation for Compile suggests that's the correct thing to do, but once again the C# compiler is dumbstruck. It says:

    Error 5 'T' is a 'type parameter' but is used like a 'variable'

    Ok? So let's use typeof(T) instead...

    Error 2 No overload for method 'Compile' takes 2 arguments

    Bwah!?!?

    Needless to say, there's no examples of how to properly use Expression<t>.Compile on MSDN that I can find...



  • I see you are supplying your service to the Expression you are trying to compile, while you should supply it to the resulting Func.

    Try it like this:

                    var compiledAction = action.Compile();
    
                    var timer = new Stopwatch();
                    timer.Start();
                    var result = compiledAction(service);
                    timer.Stop();
    

    The documentation which you found is from System.Data.Linq.CompiledQuery, I believe that is used by Entity Framework.



  • That doesn't work either; exact same two errors. If I pass only service, I get "requires two params". If I pass service, T I get "T is a type param but used like a variable", and if I pass service, typeof(T) I inexplicably get "no overload takes two params" again.

    I'm not sure what I'm doing wrong.

    Considering the error messaging Intellisense was giving me is gibberish, it might just have a corrupted cache or something. I'll try it again after a reboot tomorrow morning.



  • @blakeyrat said:

    I'm not sure what I'm doing wrong.

    You shouldn't have to pass any parameters to Compile, as per MSDN documentation. If you are asked to supply two parameters, then maybe you have some import which is screwing things up? Be aware that these Expressions live in the System.Linq.Expressions namespace.

    Also, I (just now) that you said that your web service references are static classes. Is there a reason for having those things as statics? AFAIK, that is not the default behaviour of 'Add service reference'



  • @AlexMedia said:

    You shouldn't have to pass any parameters to Compile, as per MSDN documentation.

    I didn't have to, I tried it because the other way didn't work.

    @AlexMedia said:

    Also, I (just now) that you said that your web service references are static classes.

    When I get into the office I'll look again. They might not be static, but they didn't implement IDisposible, which was the important thing for the point I was making about getting rid of the IDisposible interface.

    Also keep in mind that yesterday was my first day back after a week off and my coworkers are useless and were CONSTANTLY pulling me away from my desk, so it's possible I'm wrong about a good many things.



  • @blakeyrat said:

    I didn't have to, I tried it because the other way didn't work.

    Hmm, interesting... the code that I shared before did work for me. But that's on my machine in a very specific scenario (the one I posted) so I am sure your mileage would vary.

    When I get into the office I'll look again. They might not be static, but they didn't implement IDisposible, which was the important thing for the point I was making about getting rid of the IDisposible interface.
    When I wrote the code I had it in my mind that web service references implemented IDisposable, but I haven't used them in a while. If you don't need it, get rid of it! 😄
    Also keep in mind that yesterday was my first day back after a week off and my coworkers are useless and were CONSTANTLY pulling me away from my desk, so it's possible I'm wrong about a good many things.
    I hope you had a good week off. Colleagues needing you every other minute sounds all too familiar... 😑


  • Yeah and of course when I do get in there's a fire, and now I have to put that out before anything else.

    This project is never going to actually get done at this rate, feh.

    Anyway when I get a chance I'll give it another go.



  • OK BACK ON THIS NOW.

    Here's the code I have currently:

    public MyResponse Execute<T>(Expression<Action<IService, T>> action) where T : 3rdPartyResponse
    {
    var initialTime = DateTime.Now;
    
    var methodExpression = action.Body as MethodCallExpression;
    if (methodExpression != null)
    {
        Console.WriteLine("Name of called method: {0}", methodExpression.Method.Name);
    }
    
    var methodName = methodExpression.Method.Name;
    
    var compiledAction = action.Compile();
    
    var timer = new Stopwatch();
    timer.Start();
    var result = compiledAction(service);
    timer.Stop();
    }
    

    The error is on the line:

    var result = compiledAction(service);

    The error is "Delegate 'Action' does not take 1 arguments".

    If I hover over compiledAction(), Intellisense tells me the only valid overload is compiledAction(IService, T)



  • Ok derp. Problem was was defining the method to take an expression of an Action-- Actions are limited to methods with no return value. That should have been Func.

    Changing the method definition to this:

    public MyResponse Execute<T>(Expression<Func<ICarrierService, T>> action) where T : 3rdPartyResponse

    Appears to be correct.



  • NEW QUEEEEESTION

    I have my MethodExpression, and the Method inside of it...

    Does THIS do what I expect:

                    object argument = null;
    
                    if( methodExpression.Arguments.Any())
                    {
                        argument = methodExpression.Arguments.First();
                    }
    

    The goal here is to be able to serialize the argument passed into the method for logging purposes. In the debugger, "argument" shows up as a lot of "stuff" but seems to be a lot more than merely the argument object passed-in, so I'm not sure that's correct.



  • I'd have to see the weird extra stuff to be sure, but that certainly looks right to me.



  • I get a bunch of stuff about "CanReduce", a "DebugView"...

    (image gone)

    I had to redact like 90% of it unfortunately as the type names give away my employer and the 3rd party we're working with.

    EDIT: the Member field looks promising, but it also includes a bunch of meta-data about the argument and not, AFAICT, the argument itself. Custom Attributes, Declaring Type, Member Type, etc.



  • Yeah, that looks like it'll be difficult. It definitely should be in there, but they're basically keeping all the information they need to parse the syntax in there...



  • I serialized the results, and from the JSON structure, it looks like the actual object I want is in Expression.Value. Trying that now.

    Gruh. Ok .Expression is inaccessible, apparently? Although Newtonsoft can get a grip on it... hm.

    Ok, it's type is a System.Linq.Expressions.FieldExpression which is not accessible. You know what? I'm digging a hole here. Might as well just wrap these services the traditional way, there's not that many different API endpoints.



  • @blakeyrat said:

    The goal here is to be able to serialize the argument passed into the method for logging purposes. In the debugger, "argument" shows up as a lot of "stuff" but seems to be a lot more than merely the argument object passed-in, so I'm not sure that's correct.

    Yeah - your first Argument is an Expression as well. .NET doesn't try to actually evaluate its value unless you tell it to.

    To actually get the parameter value, you have to jump through some hoops - the way I know is to construct a () => yourArgumentExpression lambda, compile and invoke it.

    using System;
    using System.Linq;
    using System.Linq.Expressions;
    					
    public class Program
    {
    	
    	public static void Execute<T1, T2>(Expression<Func<T1, T2>> expr)
    	{
    		var methodExpression = expr.Body as MethodCallExpression; //what you have
    		var arg = methodExpression.Arguments.First(); //what you have
    		var lambda = Expression.Lambda(arg); //turn the argument expression into a parameterless lambda with the argument as a body
    		var comp = lambda.Compile(); //compile the lambda into an untyped Delegate
    		var result = comp.DynamicInvoke(); //invoke the delegate with no parameters (returns object)
    		Console.WriteLine(result.ToString()); //or cast it to T2 and do something with it, etc.
    	}
    	
    	public class Test
    	{
    		public string DoStuff(string s)
    		{
    			return s + s;
    		}
    	}
    	
    	public static void Main()
    	{
    		Execute<Test, string>(x => x.DoStuff("Hello world!"));
                    //but you can also do this - note that this will cause whatever you put as an argument to evaluate twice
    		Execute<Test, string>(x => x.DoStuff("Hel" + "lo " + "world!"));
                    //or even this
                    Execute<Test, string>(x => x.DoStuff(new String("Hello world!".ToCharArray().Reverse().ToArray())));		
    	}
    }
    


  • Wait a minute. Isn't this the place with the whole big over-engineered IOC (or whatever) framework you were complaining about before? You should ask someone who's more familiar with the framework if there's any way you can use it to generate a proxy object for you.

    I mean, this should be easy, god damn it. All you need is a simple wrapper around an object that sees the parameters that get passed in and the result that gets returned. I know .net has that functionality, otherwise mock objects couldn't exist, for testing.



  • @Buddy said:

    Wait a minute. Isn't this the place with the whole big over-engineered IOC (or whatever) framework you were complaining about before?

    We actually decided as a company to kibosh it. So it's on the way out.

    @Buddy said:

    You should ask someone who's more familiar with the framework if there's any way you can use it to generate a proxy object for you.

    I don't want a proxy of the service client, I want an actual service client. But I want to be able to dig in and examine its input and output for logging purposes.

    In any case, I already just wrote my wrappers the old-fashioned way. With a few helper methods, it's only 3 lines of my code for each API endpoint, so that's good enough.



  • No, what I'm saying is, what you've implemented is the proxy pattern

    Obviously, it's a bit confusing to talk about, because you're dealing with code that uses the network, and a network proxy is another type of proxy that you could be thinking of. But this is the literal meaning of the word proxy. The ServiceClient classes that you have implemented are proxy objects for the ServiceClientSoap classes that wcf generated.


Log in to reply