Search code examples
c#.netasp.net-mvcwcfwcftestclient

WcfTestClient - Sequence contains no elements [When value is null]


I have written a WCF service to handle the main business logic on my turned-based web game and I'm running into an issue while testing with WcfTestClient. As you can see from the signature of a method I am exposing over WCF it has several optional parameters.

public PlayerActionResult DoAction(PlayerActionType type, int uid, string pparam = null, int amount = 0, string svalue = null);

So, the type of action is definitely a requirement as well as the user id (uid) of the player performing the action, after that the parameters become optional since certain actions may or may not require another player, integer amount, or general string value (i.e. attacking another player requires another Player object, which is looked up using the name of the character[pparam]). Here is the entire implementation of the DoAction method:

 public PlayerActionResult DoAction(PlayerActionType type, int uid, string pparam = null, int amount = 0, string svalue = null) 
    {
        Player playerparam;
        Player player;
        // Verify players exist
        if (!PlayerExists(uid))
        {
            return new PlayerActionResult(false, ResultType.NotFound);
        }
        else { player = GetPlayer(uid); }

        if (pparam != null & !PlayerExists(pparam))
        {
            return new PlayerActionResult(false, ResultType.NotFound);
        }
        else { playerparam = GetPlayer(pparam); }

        // Construct action and pass parameters
        return player.DoAction(new PlayerAction(type, playerparam, amount, svalue));
    }

Given that method I decided to run a few tests to make sure this works as intended for the most part. Everything works up until I try to pass (null) into the method via WcfTestClient at which time I am given the following error:

Sequence contains no elements

Server stack trace: System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, >MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter) at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime >operation, ProxyRpc& rpc) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, >ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage >methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]:

at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, >IMessage retMsg)

at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)

at IConquestService.DoAction(PlayerActionType type, Int32 uid, String pparam, Int32 amount, String svalue)

at ConquestServiceClient.DoAction(PlayerActionType type, Int32 uid, String pparam, Int32 amount, String svalue)

I have stewed on this predicament for a while and done several searches for the "Sequence contains no elements" keywords to no avail for this specific issue. Keep in mind however that when I call this method from my MVC app everything works pretty smoothly, the action logic is called and processed with no problem. It seems to be only when I try and pass (null) as pparam within WcfTestClient. If anyone stumbles upon this and could enlighten me I would greatly appreciate it.

UPDATED:

Thanks for that suggestion! I was fiddling with it within the 15 minutes I posted this and I made some modifications which ended up fixing the problem. I kept the optional parameters and retweaked the method a bit by instead instantiating the PlayerAction object first then setting the playerparam property of that object directly within the method if the pparam string is present. Here is what it looks like now:

   public PlayerActionResult DoAction(PlayerActionType type, int uid, string pparam = null, int amount = 0, string svalue = null) 
    {
        Player player;
        PlayerAction action = new PlayerAction();
        action.type = type;
        // Verify executor exists
        if (!PlayerExists(uid))
        {
            return new PlayerActionResult(false, ResultType.NotFound);
        }
        else { player = GetPlayer(uid); }

        if (pparam != null & !PlayerExists(pparam))
        {
            if (!PlayerExists(pparam))
            {
                return new PlayerActionResult(false, ResultType.NotFound);
            }
            action.playerparam = GetPlayer(pparam);
        }

        // Construct action and pass parameters
        return player.DoAction(new PlayerAction(type, amount, svalue));
    }

Solution

  • Have you tried implementing these as overloads instead of optional parameters?

    For example:

    public PlayerActionResult DoAction(PlayerActionType type, int uid);
    public PlayerActionResult DoAction(PlayerActionType type, int uid, string pparam);
    public PlayerActionResult DoAction(PlayerActionType type, int uid, string pparam, int  amount);
    //etc...
    

    Windows Communication Foundation likely does not understand the default arguments being assigned and is simply transmitting the OperationContract as a method with two parameters in the WSDL.

    This would explain why it works in MVC, as WCF requires information transmitted in a SOAP envelope to properly decide which method to execute on the server, whereas MVC uses the route being accessed.