views:

23

answers:

1

Subject says it all: I'm creating a secure and generic wrapper to access a WCF service transparently.

A little background:

what I have done is that I've created similar business classes definition both on server and client. The server-side contains the actual logic while the client side contains only method definitions. Additionally, the client-side classes derive from a SecureFactory which implements a Call method. The body of every method of each derived class contains only a call to Call method. This Call method is responsible for invoking the server service passing such things as to the type of business class and which of its method to invoke to perform the requested operation. This approach is being designed in order to simplify security checks by restricting passing of security information to only between SecureFactory and Server service. There are tuns of other benefits which you most of already aware of.

Now here's the issue: I'm stuck at as to how to return objects (especially arrays of objects) from Server to Call method? The server may return a single business object (DataContract applied) as well as list of such objects. Since it's a generic approach, I have only Object to be used as return type. Following is the Call method

public object Call(params object[] parameters)
        {
            var mb = (new StackFrame(1).GetMethod());
                        using (Proxy.ServerClient server = new Security.BO.Proxy.ServerClient())
            {
                try
                {
                    if (((MethodInfo)mb).ReturnType.IsGenericType)
                    {
                        var response = server.InvokeForList(SecurityManager.Current.SID, SecurityManager.Current.Token, mb.DeclaringType.ToString(), mb.Name, parameters);
                        return  response.Result.ToList();
                    }
                    else
                    {
                        var response = server.Invoke(SecurityManager.Current.SID, SecurityManager.Current.Token, mb.DeclaringType.ToString(), mb.Name, parameters);
                        return response.Result;
                }
                        }
               catch (Exception ex)
                {
                    System.Diagnostics.Debugger.Break();
                }
                            }

            return null;
                    }

server methods:

public CollectionResponse InvokeForList(string SID, string token, string type, string method, object[] parameters)
        {
            // Validation here
            var t = assemblyBO.GetType(type, true);
            object BO =  Activator.CreateInstance(t);
            var mi = t.GetMethod(method);
            if (mi == null)
                throw new MethodNotImplementedException("Method " + method + " could not be found on type " + t.ToString());

            object res = mi.Invoke(BO, parameters);
// Convert list to t[]
            object list = res.GetType().GetMethod("ToArray").Invoke(res, new object[0]);
// Error here! cannot convert t[] into object[]
            return new CollectionResponse((object[])list); 
            }

The other method Invoke(...) is similar accept it returns Response object instead of CollectionResponse.


Here's the CollectionResponse class: (Response is similar:just it takes only one object)

[DataContract]
    public class CollectionResponse
    {

        [DataMember]
       private Object[] _result;
        public Object[] Result
        {
            get
            {
                return _result;
            }
        }

        public CollectionResponse(Object[] result)
        {
            this._result = result;
        }

    }

Initially I was thinking to have only one Invoke for both lists and singleton – but failed with "Connection was closed unexpectedly." still I'm not able to achieve – how can I convert T[] into object[].

Do you have any suggestion to improve it, or any other way of achieving the same?

Thanks

+1  A: 

I can see an immediate problem here. You are using reflection which is far less perfromant than the direct call.

For me, that is enough not to follow this route.

Aliostad
Server.Invoke(...) / Server.InvokeForList(...) is direct call. I have just named them like so. Yes, reflection is being used inside InvokeForList(...) to execute a method on a specified – Do you think it can be avoided for such a generic approach?
Varun
To be honest I do not see any problem that this can fix. Callers of such services still need to know how to make the call and which parameters to pass while they lose the benefit of compile time checks. It is an interesting thing to do, sure, but not a useful one.
Aliostad
If you can share business object across server/cleint
Varun
Then this approach has many benefits (note my client app is a smart client one, so sharing is perfectly valid). Also, as I wrote, only the Call method is generic — not the business classes' methods, which can only make a call to Call method in their body (compile-time checking is insured).
Varun
Here's an example of a business object: public class SampleBO : SecureFactory { public List<int> GetPrime(int start, int end) { return (List<int>)base.Call(start, end); } }
Varun