none
Better than "Add Service Reference" with reuse objects RRS feed

  • Question

  • Hi all,

    Its possible that I'm not doing something right or there is something wrong with my setup, but I'm not using the P&P software factory, just VS2012 and nearly OOTB web services (8 of them) to tier my data layer from website.

    Thing is this is a low spec'd system and very dynamic and the "Add Service reference" and "update service reference" is very slow workflow, additionally you can't benefit (in my setup) from "right click generate stub" from client side, because the Interface/contract is in the automatically generated "Reference.cs" namespace rather than the actual "true" interface that is in the actual web service...

    Hopefully this is clear enough what I'm going through... so even though I'm using "reuse" referenced assemblies it doesn't seem to have any impact on the Service and Interfaces generated in this reference file - only shared objects are reused (eg: domain objects are "the same" - eg: CustomerInfo *IS* shared, but the service/contract are not...

    presumably the CLIENT must be generated, but I would have hoped that the IService would have been shared... but perhaps the svcutil.exe thing doesn't "know" we own both sides of the wire, so I may be expecting too much...

    Anyway I discovered that you can basically do a "nicer" version of the same thing by dynamically creating the channel between the client/server by using the generic "ChannelFactory<T>" class whcih is awesome, and so by borrowing from many places around the internet I've come up with this (heavily borrowed from http://stackoverflow.com/questions/573872/what-is-the-best-workaround-for-the-wcf-client-using-block-issue ):

        public static class Service<T>
        {
            // each type "T" will have its own static instance of this factory
            private static ChannelFactory<T> _channelFactory = new ChannelFactory<T>("WSHttpBinding_" + typeof(T).Name);
            //shorthand for static constructor initalization - typeof() interface means NAME in config of ENDPOINT must be contractname
            //NOTE: the hard coded bindingprefix on the endpoint naming convention... eg: if not using WSHttpBinding and also if there is Nameconflict...
    
            public static void Use(Action<T> codeBlock)
            {
                IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
                bool success = false;
                try
                {
                    codeBlock((T)proxy);
                    proxy.Close();
                    success = true;
                }
                catch (CommunicationException e)
                {
                    // possibly log error, possibly clean up
                    proxy.Abort();
                }
                catch (TimeoutException e)
                {
                    // possibly log error, possibly clean up
                    proxy.Abort();
                }
                catch (Exception e)
                {
                    // possibly log error, possibly clean up
                    proxy.Abort();
                    throw;
                }
            }
        }

    This is working beautifully so far, but I have one gripe, in that I've had to change a lot of my code to accommodate its usage in the following way:

    <...myclass with depency on myService...>
    public IMyService svcReference;//set manually or assigned in constructor maybe IoC not sure yet
    public void GoGetData(){
    try{var somedata = svcReference.GetSomeData();}
    catch(exception e){ Debug.WriteLine("Connection issue with service!");}
    }
    <... more class... >

    has changed to:

    <...myclass with depency on myService...>
    public void GoGetData(){
    MyDataType somedata = null;
    Service<IMyService>.Use(svc = >somedata = GetSomeData());
    }
    <... more class... >

    Problem is two-fold

    - its introducing dependency on "Service<T>" which (I think) is gonna make it harder to test if I want to make a dummy service, but maybe I'm wrong...

    - although I appreciated the simpler code (moving the try/catch) the BLOCK (I think that's what this passing delegate function is called), I'm worried about how to handle the error with this workflow... or is this deferring the error handling to the "Service<T>" and allowing the child class to just pretend like errors don't happen (metaphorically).

    eg: next lines of code might be
    if (somedata != null)...

    Ideally I would think that:

    • MyClass should accept the contract "IMyService" and really not know much about it other than it does 'SomeMethod' (for example)
    • But then there is no way ( that I've come up with/come across) to do the "if error "Abort/Close" thing on the channel IN the class as it should know nothing of the "open/close/abort" if its just an interface... - which is fine if the class only used one function but what if more than one function could be used during the life of the class? Perhaps some "IDisposable" type approach is needed?! but all the stuff I've read warns of race conditions/masking errors.
    • If the service is passed in, then who/how is it instantiated, opened/closed/aborted, and how to cope when it invariably dies and throws an error for whatever reason IN the class that only knows it as an IMyService and doesn't know that its actually a remote service that just timed out?
    • The code that says "Catch(...){proxy.Abort;}" bothers me because I feel like its swallowing the actual error and the service in the "dumb class" doesn't know this, but the action will not be successful... so "somedata" will not be set but there will not be an error thrown... perhaps this is INTENTIONAL and youre expectedt to check for - If (somedata != null) and continue on with this in mind for the system...?!

    Any advice/direction appreciated.

    Saturday, February 15, 2014 3:58 AM

All replies

  • For dynamic service factories you can use RESTful WCF services and invoke them from your client.
    Saturday, February 15, 2014 9:11 AM
  • I really don't know what you mean by;

    "dynamic service factories" (specifically or if its just a general term for service factories created on the fly)

    or by "RESTful WCF services and invoke them from your client" and how this solves my issues?

    Can you either elaborate or put some links in your info, because as it is your comment doesn't help me much...

    Thanks anyway. :)

    Monday, February 17, 2014 6:39 AM