1

I have the following code:

public class TardiisServiceAsync
{
    private static TardiisServiceAsync instance;

    public static TardiisServiceAsync Instance
    {
        //Singleton
        get
        {
            if (instance == null)
            {
                instance = new TardiisServiceAsync();
            }
            return instance;
        }
    }
    public const string CACHE_PREFIX_TARDIIS_SERVICE = "TardiisServiceAsync_";
    public static Dictionary<string, Tuple<string, object>> clients = new Dictionary<string, Tuple<string, object>>();
    public delegate Task<IEnumerable<object>> GetServiceList(object client, string connectionId, TardiisServiceParameters parameters = null);


    public async Task<IEnumerable<object>> GetDemographicGroupsDelegateAsync(object client, string connectionId, TardiisServiceParameters parameters = null)
    {
        //Returns IEnumerable<object> task
        var test = Convert(client.GetType().GetMethod("GetDemographicGroupsAsync").Invoke(client, new object[] { connectionId }));
        var result = await test;
        return (IEnumerable<object>)result;
    }

    public async Task<IdNameObject[]> GetDemographicGroupsAsync()
    {
        //This task is called from hight level class
        Task<IdNameObject[]> cacheValue = null;
        string cacheKey = CACHE_PREFIX_TARDIIS_SERVICE + Membership.GetUser().UserName + "GetDemographicGroupsAsync" + GetMarketCode();

        if (ConfigurationManager.AppSettings[ConstantsHelper.FIELD_CONFIG_USE_CACHE_KEY] != null && bool.Parse(ConfigurationManager.AppSettings[ConstantsHelper.FIELD_CONFIG_USE_CACHE_KEY]))
        {
            if (HttpContext.Current.Cache[cacheKey] == null)
            {
                var taskResult = InitializeTardiisInstanceAndCallService(GetDemographicGroupsDelegateAsync);
                var test = await taskResult;
                cacheValue = (Task<IdNameObject[]>)HttpContext.Current.Cache[cacheKey];//This is not implemented yet
            } 
        }

        return await cacheValue;
    }

    public static Task<T> Convert<T>(T value)
    {
        return Task.FromResult<T>(value);
    }

    public static EnumHelper.EnumMarketCode GetMarketCode(EnumHelper.EnumMarketCode? marketCode = null)
    {
        //Returns market code
        if (!marketCode.HasValue)
            return (EnumHelper.EnumMarketCode.US);
        else
            return marketCode.Value;
    }

    private Task<IEnumerable<object>> InitializeTardiisInstanceAndCallService(GetServiceList getServiceList, TardiisServiceParameters parameters = null, EnumHelper.EnumMarketCode? marketCode = null, bool creatingConnectionsForAllCountries = false, string username = "")
    {
        //Get the instance and call the tardiis correct tardiis service depends on the market code
        marketCode = GetMarketCode(marketCode);
        MembershipUser membershipUser = Membership.GetUser();
        string currentUsername = (membershipUser != null ? membershipUser.UserName : username);
        string currentKey = currentUsername + "_" + marketCode;

        if (clients.ContainsKey(currentKey))
        {
            try
            {
                //check if the connection is still active, or we should reconnect.
                return getServiceList(clients[currentKey].Item2, clients[currentKey].Item1, parameters);
            }
            catch (Exception) { }
        }
        //At this point there is no connection, we need to open it.                            
        object client = TardiisServiceFactory.GetService(marketCode.Value);

        UserDTO userDTO = UserService.Instance.GetByUsername(currentUsername);
        TardiisUserDTO tardiisUserDTO = UserService.Instance.GetTardiisUserByUserIdAndMarketCode(userDTO.ID, marketCode.Value.ToString());

        if (tardiisUserDTO.TardiisUsername == null)
        {
            if (creatingConnectionsForAllCountries)
                return null;
            else
                throw new TardiisLoginException("Please enter your credentials");
        }

        object user = TardiisServiceFactory.GetUser(marketCode.Value, tardiisUserDTO.TardiisUsername, tardiisUserDTO.TardiisPassword);
        string connectionId;
        try
        {
            connectionId = (string)client.GetType().GetMethod("InitConnection").Invoke(client, new object[] { user });
        }
        catch (FaultException ex)
        {
            // This exception is catched globally by BaseController and prompts the user to enter his
            // tardiis credentials again
            throw new TardiisLoginException(ex.InnerException.Message, ex);
        }
        catch (TargetInvocationException ex)
        {
            // This exception is catched globally by BaseController and prompts the user to enter his
            // tardiis credentials again
            throw new TardiisLoginException(ex.InnerException.Message, ex);
        }

        clients[currentKey] = new Tuple<string, object>(connectionId, client);
        return getServiceList(clients[currentKey].Item2, clients[currentKey].Item1, parameters);
    }

    private void AddToCache(string key, object value)
    {
        HttpContext.Current.Cache.Add(key, value, null, DateTime.Now.AddMinutes(30), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
    }

}

I am getting the following error message:

Unable to cast object of type 'System.Threading.Tasks.Task[System.Object] to type 'System.Collections.Generic.IEnumerable1[System.Object].

The result of the task is a TypedClass[].

How can I return as a Task<IEnumerable<object>> on the call method.

This is a "copy" of a another class that have similar logic but in a synchronized way. The idea is change some methods so they can be run synchronously.

Thank you!

Marcelo Arias
  • 11
  • 1
  • 3
  • 1
    var taskResult = task.Result; this is not a task when you add .result it will be an enumerable or other type you use – gandalf Mar 26 '19 at 17:46
  • Hi @Pliskin, thank you for your response, I understand that, but I cannot convert the `Task` result to `Task>`. Thank you. – Marcelo Arias Mar 26 '19 at 17:54
  • what is the type of taskResult and the param type of convert method? – gandalf Mar 26 '19 at 17:56
  • The result is `Task` a custom class array. Below i leave the code of the Convert method: `public static Task Convert(T value) { return Task.FromResult(value); }` – Marcelo Arias Mar 26 '19 at 17:59
  • Check the updated code and let me know if it works, or add this as param of Convert resultado.ToList() – gandalf Mar 26 '19 at 18:00
  • Thank you, but now I am getting the next compilation error: `Cannot implicity convert type 'System,Threading.Task.Task' to 'System,Collections.Generic.IEnumerable'` – Marcelo Arias Mar 26 '19 at 18:08
  • Why are you invoking this through reflection? – johnny 5 Mar 26 '19 at 18:12
  • Did you try to pass task variable to convert method? – gandalf Mar 26 '19 at 18:14
  • @johnny5 bacause the param client(type object) call diferents service reference(related to the user country) depending on what it has loaded. If you like I can share you the entire block code. – Marcelo Arias Mar 26 '19 at 18:23
  • @MarceloArias yeah, share the whole block maybe I can help you avoid the issue, it rare to need reflection – johnny 5 Mar 26 '19 at 18:25
  • might need a 'yield return await' since it is a thread. https://stackoverflow.com/questions/5061761/is-it-possible-to-await-yield-return-dosomethingasync – Alex Moreno Mar 26 '19 at 18:30
  • I already posted the entire class code. The goal of that class is replicate another class but call async service methods instead of sync ones. Thank you for the help you are giving me. – Marcelo Arias Mar 26 '19 at 18:37
  • Is `task` of type `Task<...>`? If yes why do you not await it? – Ackdari Mar 26 '19 at 19:02

2 Answers2

0
    public async Task<IEnumerable<object>> GetDemographicGroupsDelegateAsync(object client, string connectionId, TardiisServiceParameters parameters = null)
{

    var test = Convert(client.GetType().GetMethod("GetDemographicGroupsAsync").Invoke(client, new object[] { connectionId }));
    var result = await test;
    var resultado = test.Result;
    return Convert(new List<Object>{resultado});
}
gandalf
  • 451
  • 5
  • 18
0

If you have an IEnumerable<A> like an array you can cast it to IEnumerable<object> using the Linq-Methode Cast<object>()

public async Task<IEnumerable<object>> GetDemographicGroupsDelegateAsync(object client, string connectionId, TardiisServiceParameters parameters = null)
{

    var test = Convert(client.GetType().GetMethod("GetDemographicGroupsAsync").Invoke(client, new object[] { connectionId }));
    var task = await test;
    var taskResult = await task;
    return taskResult.Cast<object>();
}
Ackdari
  • 3,222
  • 1
  • 16
  • 33
  • Hi Ackdari, thank you but the variable taskResullt is an object type, and is not awatiable, I am right?. – Marcelo Arias Mar 27 '19 at 12:48
  • @MarceloArias well, I don't know what the types of your objects are? I may be abel to clarify my answer if you tell me what the type of `test` and what the type of `task` is. – Ackdari Mar 27 '19 at 21:15