public bool PreProcess(PayloadMessage message)
        {
            IGrain sender      = message.SenderIdentifer;
            ulong  sequenceNum = message.SequenceNumber;

            switch (CheckMessage(sender, sequenceNum))
            {
            case MessageStatus.Vaild:
                inSequenceNumberMap[sender]++;
                return(true);

            case MessageStatus.Ahead:
                if (!stashedPayloadMessages.ContainsKey(sender))
                {
                    stashedPayloadMessages[sender] = new Dictionary <ulong, Pair <bool, List <TexeraTuple> > >();
                }
                if (!stashedPayloadMessages[sender].ContainsKey(sequenceNum))
                {
                    stashedPayloadMessages[sender].Add(sequenceNum, new Pair <bool, List <TexeraTuple> >(message.IsEnd, message.Payload));
                }
                break;

            case MessageStatus.Duplicated:
                break;
            }
            return(false);
        }
Esempio n. 2
0
        public static string Format(MethodInfo method, InvokeMethodRequest request, IGrain grain)
        {
            if (method == null)
            {
                return("Unknown");
            }

            if (!(grain is IActorGrain))
            {
                return(method.Name);
            }

            if (method.Name != nameof(IActorGrain.ReceiveAsk) &&
                method.Name != nameof(IActorGrain.ReceiveTell) &&
                method.Name != nameof(IActorGrain.ReceiveNotify))
            {
                return(method.Name);
            }

            var argumentType = request.Arguments[0]?.GetType();

            if (argumentType == null)
            {
                return($"{method.Name}(NULL)");
            }

            return(argumentType.IsGenericType
                ? $"{argumentType.Name}<{string.Join(",", argumentType.GenericTypeArguments.Select(x => x.Name))}>"
                : argumentType.Name);
        }
 public void CheckStashed(ref List <TexeraTuple> batchList, ref bool isEnd, IGrain sender)
 {
     if (stashedPayloadMessages.ContainsKey(sender))
     {
         if (!inSequenceNumberMap.ContainsKey(sender))
         {
             inSequenceNumberMap[sender] = 0;
         }
         ulong currentSequenceNumber = inSequenceNumberMap[sender];
         Dictionary <ulong, Pair <bool, List <TexeraTuple> > > currentMap = stashedPayloadMessages[sender];
         while (currentMap.ContainsKey(currentSequenceNumber))
         {
             if (batchList == null)
             {
                 batchList = new List <TexeraTuple>();
             }
             Pair <bool, List <TexeraTuple> > pair = currentMap[currentSequenceNumber];
             isEnd |= pair.First;
             if (pair.Second != null)
             {
                 batchList.AddRange(pair.Second);
             }
             currentMap.Remove(currentSequenceNumber);
             currentSequenceNumber++;
             inSequenceNumberMap[sender]++;
         }
     }
 }
Esempio n. 4
0
 public static string GetPrimaryKeyStringFromGrain(IGrain grain)
 {
     //TODO: Check to make sure grain is of type IGrainWithStringKey
     string stringPrimaryKey; 
     Guid guidPrimaryKey = grain.GetPrimaryKey(out stringPrimaryKey);
     return stringPrimaryKey;
 }
Esempio n. 5
0
        internal static IGrainIdentity GetGrainIdentity(IGrain grain)
        {
            var grainBase = grain as Grain;

            if (grainBase != null)
            {
                if (grainBase.Identity == null)
                {
                    throw new ArgumentException(WRONG_GRAIN_ERROR_MSG, "grain");
                }
                return(grainBase.Identity);
            }

            var grainReference = grain as GrainReference;

            if (grainReference != null)
            {
                if (grainReference.GrainId == null)
                {
                    throw new ArgumentException(WRONG_GRAIN_ERROR_MSG, "grain");
                }
                return(grainReference.GrainId);
            }

            throw new ArgumentException(String.Format("GetGrainIdentity has been called on an unexpected type: {0}.", grain.GetType().FullName), "grain");
        }
Esempio n. 6
0
        /// <summary>
        /// Returns runtime identity of the given grain
        /// </summary>
        /// <param name="grain">Runtime grain instance</param>
        /// <returns>Id assigned to the grain</returns>
        public static string Of(IGrain grain)
        {
            string id;

            grain.GetPrimaryKeyLong(out id);
            return(id);
        }
Esempio n. 7
0
        public static string GetReadableName(IGrain grain)
        {
            string ext1;
            string guidPrefix = grain.GetPrimaryKey(out ext1).ToString().Substring(0, 8);

            return(guidPrefix + " " + ext1);
        }
Esempio n. 8
0
 /// <summary>
 /// Gets the target fake reminder by searching across all silos.
 /// </summary>
 public FakeReminder GetReminder(IGrain grain, string name)
 {
     return(ReminderRegistryGroups[TestClusterId]
            .Select(_ => _.GetReminder((GrainReference)grain, name).Result)
            .Where(_ => _ != null)
            .SingleOrDefault());
 }
Esempio n. 9
0
        /// <summary>
        /// Returns a new <see cref="IJournal"/>, initialized with the provided <paramref name="actor"/>.
        /// </summary>
        /// <param name="actor">
        /// The actor.
        /// </param>
        /// <returns>
        /// A new <see cref="IJournal"/>, initialized for the provided <paramref name="actor"/>.
        /// </returns>
        public Task <IJournal> Create(IGrain actor)
        {
            var id      = actor.GetIdString();
            var journal = Journal.GetOrAdd(id, _ => new InMemoryJournal());

            return(Task.FromResult <IJournal>(journal));
        }
Esempio n. 10
0
        static string IdentityOf(IGrain grain)
        {
            string identity;

            grain.GetPrimaryKeyLong(out identity);
            return(identity);
        }
Esempio n. 11
0
        public static string LoggingIdentifier(this IGrain grain)
        {
            var type = grain.GetType();

            try {
                string temp = null;
                if (typeof(IGrainWithIntegerKey).IsAssignableFrom(type))
                {
                    return($"[{grain.GetPrimaryKeyLong()}] ");
                }
                else if (typeof(IGrainWithIntegerCompoundKey).IsAssignableFrom(type))
                {
                    var key = grain.GetPrimaryKeyLong(out temp);
                    return($"[{key} {temp}] ");
                }
                else if (typeof(IGrainWithGuidKey).IsAssignableFrom(type))
                {
                    return($"[{grain.GetPrimaryKey()}] ");
                }
                else if (typeof(IGrainWithGuidCompoundKey).IsAssignableFrom(type))
                {
                    var key = grain.GetPrimaryKey(out temp);
                    return($"[{key} {temp}] ");
                }
                else if (typeof(IGrainWithStringKey).IsAssignableFrom(type))
                {
                    return($"[{grain.GetPrimaryKeyString()}] ");
                }
            } catch { } // Don't throw for logging methods.

            return(string.Empty);
        }
Esempio n. 12
0
        /// <summary>
        /// Returns the id of the actor as a <see cref="string"/>.
        /// </summary>
        /// <param name="actor">
        /// The actor.
        /// </param>
        /// <returns>
        /// The id of the actor as a <see cref="string"/>.
        /// </returns>
        public static string GetIdString(this IGrain actor)
        {
            var guidKey = actor as IGrainWithGuidKey;

            if (guidKey != null)
            {
                var typedActor = guidKey;
                return(typedActor.GetPrimaryKey().ToString("N", CultureInfo.InvariantCulture));
            }

            var stringKey = actor as IGrainWithStringKey;

            if (stringKey != null)
            {
                var typedActor = stringKey;
                return(typedActor.GetPrimaryKeyString());
            }

            var intKey = actor as IGrainWithIntegerKey;

            if (intKey != null)
            {
                var typedActor = intKey;
                return(typedActor.GetPrimaryKeyLong().ToString("X16", CultureInfo.InvariantCulture));
            }

            throw new NotSupportedException("Actor key type not supported");
        }
Esempio n. 13
0
 public override void SendBatchedMessages(IGrain senderIdentifier)
 {
     foreach (Pair <int, List <TexeraTuple> > pair in MakeBatchedPayloads())
     {
         receivers[pair.First].Send(new PayloadMessage(senderIdentifier, outputSequenceNumbers[pair.First]++, pair.Second, false));
     }
 }
Esempio n. 14
0
        public static string GetPrimaryKeyStringFromGrain(IGrain grain)
        {
            //TODO: Check to make sure grain is of type IGrainWithStringKey
            string stringPrimaryKey;
            Guid   guidPrimaryKey = grain.GetPrimaryKey(out stringPrimaryKey);

            return(stringPrimaryKey);
        }
Esempio n. 15
0
 public MethodInvocation(long rpcId, IGrain grain, string methodName, Task task)
 {
     RequestTime = DateTime.Now;
     RpcId       = rpcId;
     Grain       = grain;
     MethodName  = methodName;
     Task        = task;
 }
Esempio n. 16
0
 /// <summary>
 /// Gets the fake grain storage item for the given grain by searching across all silos.
 /// </summary>
 public IGrainState GetGrainState(Type implementationType, string name, IGrain grain)
 {
     return(GrainStorageGroups[TestClusterId]
            .SelectMany(_ => _.Storage)
            .Where(_ => _.Key.Item1 == $"{implementationType.FullName}{(name == null ? "" : $",{typeof(PersistentGrain).Namespace}.{name}")}")
            .Where(_ => _.Key.Item2.Equals((GrainReference)grain))
            .Select(_ => _.Value)
            .SingleOrDefault());
 }
        public async Task SetGrainState <TGrain, TGrainState>(IGrain grain, TGrainState grainState, string storageProviderName)
            where TGrain : Grain <TGrainState>, IGrain
            where TGrainState : new()
        {
            EnsureClusterIsRunning();

            var storageProvider = ClusterServices.GetServiceByName <IGrainStorage>(storageProviderName);
            await storageProvider.WriteStateAsync(typeof(TGrain).FullName, grain as GrainReference, new GrainState <TGrainState>(grainState));
        }
Esempio n. 18
0
        public string CreateGrainDirectory(IGrain grain)
        {
            var grainFolder = Path.Combine(Location, grain.Name);

            Directory.CreateDirectory(grainFolder);
            SetDirectoryPermissions(grainFolder);

            return(grainFolder);
        }
Esempio n. 19
0
 public Task <List <IGrain> > GetMultipleGrainInterfaces_List()
 {
     IGrain[] grains = new IGrain[5];
     for (int i = 0; i < grains.Length; i++)
     {
         grains[i] = GrainFactory.GetGrain <ITestGrain>(i);
     }
     return(Task.FromResult(grains.ToList()));
 }
Esempio n. 20
0
        public async Task Invoke(IGrain grain, HttpContext context)
        {
            var   grainCall = (Task)this._methodInfo.Invoke(grain, await this.GetParameters(context));
            await grainCall;

            if (this._getResult != null)
            {
                object result = this._getResult.Invoke(null, new[] { grainCall });

                if (result != null)
                {
                    string contentType = string.Empty;
                    if (context.Request.Headers.TryGetValue("accept", out StringValues val))
                    {
                        contentType = val.FirstOrDefault();
                    }
                    else
                    {
                        contentType = context.Request.ContentType;
                    }
                    context.Response.ContentType = contentType;

                    if (this._isIGrainHttpResultType)
                    {
                        var httpResult = (IGrainHttpResult)result;
                        context.Response.StatusCode = (int)httpResult.StatusCode;
                        if (httpResult.ResponseHeaders?.Count > 0)
                        {
                            foreach (var header in httpResult.ResponseHeaders)
                            {
                                context.Response.Headers[header.Key] = header.Value;
                            }
                        }

                        if (httpResult.Body != null)
                        {
                            var serialized = await this._mediaTypeManager.Serialize(contentType, httpResult.Body, context.Response.BodyWriter);

                            if (!serialized)
                            {
                                await context.Response.WriteAsync(httpResult.Body.ToString());
                            }
                        }
                    }
                    else
                    {
                        var serialized = await this._mediaTypeManager.Serialize(contentType, result, context.Response.BodyWriter);

                        if (!serialized)
                        {
                            await context.Response.WriteAsync(result.ToString());
                        }
                    }
                }
            }
        }
        public async Task <TGrainState> GetGrainState <TGrain, TGrainState>(IGrain grain, string storageProviderName)
            where TGrain : Grain <TGrainState>, IGrain
            where TGrainState : new()
        {
            var storageProvider = ClusterServices.GetServiceByName <IGrainStorage>(storageProviderName);
            var grainState      = new GrainState <TGrainState>();
            await storageProvider.ReadStateAsync(typeof(TGrain).FullName, grain as GrainReference, grainState);

            return(grainState.State);
        }
Esempio n. 22
0
        public Task <IGrain[]> GetMultipleGrainInterfaces_Array()
        {
            var grains = new IGrain[5];

            for (var i = 0; i < grains.Length; i++)
            {
                grains[i] = GrainFactory.GetGrain <ITestGrain>(i);
            }
            return(Task.FromResult(grains));
        }
Esempio n. 23
0
        public Task <string> GetActivationAddress(IGrain grain)
        {
            var grainId = ((GrainReference)grain).GrainId;

            if (this.catalog.FastLookup(grainId, out var addresses))
            {
                return(Task.FromResult(addresses.Addresses.Single().ToString()));
            }

            return(Task.FromResult <string>(null));
        }
        public Task WaitForStateOperationAsync <TGrain, TGrainState>(IGrain grain, MockMemoryStorageProvider.Operation operation, string storageProviderName, int calls = 1, object args = null)
            where TGrain : Grain <TGrainState>, IGrain
            where TGrainState : new()
        {
            var storageProvider = ClusterServices.GetServiceByName <IGrainStorage>(storageProviderName) as MockMemoryStorageProvider;

            if (storageProvider == null)
            {
                throw new Exception("Storage provider must be a MockMemoryStorageProvider");
            }
            return(storageProvider.GetOperationAwaitable(typeof(TGrain).FullName, grain as GrainReference, operation, calls, args));
        }
Esempio n. 25
0
        public async void SendEndMessages(IGrain senderIdentifier)
        {
            PayloadMessage message = MakeLastMessage(senderIdentifier, sequenceNumber);

            if (message != null)
            {
                ++sequenceNumber;
                await stream.OnNextAsync(message.AsImmutable());
            }
            message = new PayloadMessage(senderIdentifier, sequenceNumber++, null, true);
            await stream.OnNextAsync(message.AsImmutable());
        }
Esempio n. 26
0
 public override void SendBatchedMessages(IGrain senderIdentifier)
 {
     while (true)
     {
         PayloadMessage message = MakeBatchedMessage(senderIdentifier, outputSequenceNumbers[roundRobinIndex]);
         if (message == null)
         {
             break;
         }
         RoundRobinSending(message);
     }
 }
Esempio n. 27
0
        protected PayloadMessage MakeLastMessage(IGrain senderIdentifier, ulong sequenceNumber)
        {
            if (outputRows.Count == 0)
            {
                return(null);
            }
            List <TexeraTuple> payload = new List <TexeraTuple>();

            payload.AddRange(outputRows);
            outputRows = new Queue <TexeraTuple>();
            return(new PayloadMessage(senderIdentifier, sequenceNumber, payload, false));
        }
Esempio n. 28
0
 public override void SendEndMessages(IGrain senderIdentifier)
 {
     foreach (Pair <int, List <TexeraTuple> > pair in MakeLastPayload())
     {
         receivers[pair.First].Send(new PayloadMessage(senderIdentifier, outputSequenceNumbers[pair.First]++, pair.Second, false));
     }
     for (int i = 0; i < receivers.Count; ++i)
     {
         PayloadMessage message = new PayloadMessage(senderIdentifier, outputSequenceNumbers[i]++, null, true);
         receivers[i].Send(message);
     }
 }
Esempio n. 29
0
        public void SendEndMessages(IGrain senderIdentifier)
        {
            PayloadMessage message = MakeLastMessage(senderIdentifier, seqNum);

            if (message != null)
            {
                seqNum++;
                unit.Send(message);
            }
            message = new PayloadMessage(senderIdentifier, seqNum, null, true);
            unit.Send(message);
        }
Esempio n. 30
0
 public async void SendBatchedMessages(IGrain senderIdentifier)
 {
     while (true)
     {
         PayloadMessage message = MakeBatchedMessage(senderIdentifier, sequenceNumber);
         if (message == null)
         {
             break;
         }
         ++sequenceNumber;
         await stream.OnNextAsync(message.AsImmutable());
     }
 }
        /// <summary>
        /// Returns a new <see cref="IJournal"/>, initialized with the provided actor.
        /// </summary>
        /// <param name="actor">
        /// The actor.
        /// </param>
        /// <returns>
        /// A new <see cref="IJournal"/>, initialized with the provided actor.
        /// </returns>
        public async Task<IJournal> Create(IGrain actor)
        {
            var table = Tables.GetOrAdd(
                actor.GetKind(), 
                async _ =>
                {
                    var t = this.client.GetTableReference(actor.GetKind() + TableNameSuffix);
                    await t.CreateIfNotExistsAsync();
                    return t;
                });

            return new AzureTableJournal(actor.GetIdString(), await table, this.jsonSettings);
        }
Esempio n. 32
0
        /// <summary>
        /// Returns a new <see cref="IJournal"/>, initialized with the provided actor.
        /// </summary>
        /// <param name="actor">
        /// The actor.
        /// </param>
        /// <returns>
        /// A new <see cref="IJournal"/>, initialized with the provided actor.
        /// </returns>
        public async Task <IJournal> Create(IGrain actor)
        {
            var table = Tables.GetOrAdd(
                actor.GetKind(),
                async _ =>
            {
                var t = this.client.GetTableReference(actor.GetKind() + TableNameSuffix);
                await t.CreateIfNotExistsAsync();
                return(t);
            });

            return(new AzureTableJournal(actor.GetIdString(), await table, this.jsonSettings));
        }
Esempio n. 33
0
        // capture stats
        async Task<object> InvokeInterceptor(MethodInfo targetMethod, InvokeMethodRequest request, IGrain grain, IGrainMethodInvoker invoker)
        {
            // round down to nearest 10 seconds to group results
            var grainName = grain.GetType().FullName;
            var stopwatch = Stopwatch.StartNew();

            // invoke grain
            object result = null;
            if (this.innerInterceptor != null)
            {
                result = await this.innerInterceptor(targetMethod, request, grain, invoker);
            }
            else
            {
                result = await invoker.Invoke(grain, request);
            }

            stopwatch.Stop();

            var elapsedMs = (double)stopwatch.ElapsedTicks / TimeSpan.TicksPerMillisecond;

            var key = $"{grainName}.{targetMethod?.Name ?? "Unknown"}";

            grainTrace.AddOrUpdate(key, _ => {
                return new GrainTraceEntry
                {
                    Count = 1,
                    SiloAddress = siloAddress,
                    ElapsedTime = elapsedMs,
                    Grain = grainName,
                    Method = targetMethod?.Name ?? "Unknown",
                    Period = DateTime.UtcNow
                };
            },
            (_, last) => {
                last.Count += 1;
                last.ElapsedTime += elapsedMs;
                return last;
            });

            return result;
        }
Esempio n. 34
0
 static string IdentityOf(IGrain grain)
 {
     return (grain as IGrainWithStringKey).GetPrimaryKeyString();
 }
Esempio n. 35
0
 public Task<List<IGrain>> GetMultipleGrainInterfaces_List()
 {
     IGrain[] grains = new IGrain[5];
     for (int i = 0; i < grains.Length; i++)
     {
         grains[i] = GrainFactory.GetGrain<ITestGrain>(i);
     }
     return Task.FromResult(grains.ToList());
 }
Esempio n. 36
0
        public void OnInvoke(InvokeMethodRequest request, IGrain grain)
        {
            // (NOT YET AVAILABLE) Interface name is available from: <c>grainReference.InterfaceName</c>
            // (NOT YET AVAILABLE) Method name is available from: <c>grainReference.GetMethodName(request.InterfaceId, request.MethodId)</c>
            // GrainId is available from: <c>grainReference.GrainId</c>
            // PrimaryKey is availabe from: <c>grainReference.GrainId.GetPrimaryKeyLong()</c> or <c>grainReference.GrainId.GetPrimaryKey()</c> depending on key type.
            // Call arguments are available from: <c>request.Arguments</c> array

            TotalCalls++;

            Console.WriteLine("OnInvoke TotalCalls={0}", TotalCalls);

            try
            {
                Console.WriteLine("OnInvoke called for Grain={0} PrimaryKey={1} GrainId={2} with {3} arguments",
                    grain.GetType().FullName,
                    ((GrainReference) grain).GrainId.GetPrimaryKeyLong(),
                    ((GrainReference) grain).GrainId,
                    request.Arguments != null ? request.Arguments.Length : 0);
            }
            catch (Exception exc)
            {
                Console.WriteLine("**** Error OnInvoke for Grain={0} GrainId={1} with {2} arguments. Exception = {3}",
                    grain.GetType().FullName,
                    ((GrainReference)grain).GrainId,
                    request.Arguments != null ? request.Arguments.Length : 0,
                    exc);
            }

            if (setActivityId != Guid.Empty)
            {
                Trace.CorrelationManager.ActivityId = setActivityId;
                Console.WriteLine("OnInvoke Set ActivityId={0}", setActivityId);
            }
            Console.WriteLine("OnInvoke Current ActivityId={0}", Trace.CorrelationManager.ActivityId);
        }
        // capture stats
        async Task<object> InvokeInterceptor(MethodInfo targetMethod, InvokeMethodRequest request, IGrain grain, IGrainMethodInvoker invoker)
        {
            var grainName = grain.GetType().FullName;
            var stopwatch = Stopwatch.StartNew();

            // invoke grain
            object result = null;
            var isException = false;

            try
            {
                if (this.innerInterceptor != null)
                {
                    result = await this.innerInterceptor(targetMethod, request, grain, invoker);
                }
                else
                {
                    result = await invoker.Invoke(grain, request);
                }
            }
            catch (Exception ex)
            {
                isException = true;
                throw;
            }
            finally
            {

                try
                {
                    stopwatch.Stop();

                    var elapsedMs = (double)stopwatch.ElapsedTicks / TimeSpan.TicksPerMillisecond;

                    var key = string.Format("{0}.{1}", grainName, targetMethod?.Name ?? "Unknown");

                    grainTrace.AddOrUpdate(key, _ =>
                    {
                        return new GrainTraceEntry
                        {
                            Count = 1,
                            ExceptionCount = (isException ? 1 : 0),
                            SiloAddress = siloAddress,
                            ElapsedTime = elapsedMs,
                            Grain = grainName ,
                            Method = targetMethod?.Name ?? "Unknown",
                            Period = DateTime.UtcNow
                        };
                    },
                    (_, last) =>
                    {
                        last.Count += 1;
                        last.ElapsedTime += elapsedMs;
                        if (isException) last.ExceptionCount += 1;
                        return last;
                    });
                }
                catch (Exception ex)
                {
                    this.Logger.Error(100002, "error recording results for grain", ex);
                }
            }

            return result;
        }
Esempio n. 38
0
 public Task<IGrain[]> GetMultipleGrainInterfaces_Array()
 {
     var grains = new IGrain[5];
     for (var i = 0; i < grains.Length; i++)
     {
         grains[i] = GrainFactory.GetGrain<ITestGrain>(i);
     }
     return Task.FromResult(grains);
 }
Esempio n. 39
0
        protected void AssertIsInRange(long val, long lowerLimit, long upperLimit, IGrain grain, string reminderName, TimeSpan sleepFor)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("Grain: {0} Grain PrimaryKey: {1}, Reminder: {2}, SleepFor: {3} Time now: {4}",
                grain.ToString(), grain.GetPrimaryKey(), reminderName, sleepFor, Time());
            sb.AppendFormat(
                " -- Expecting value in the range between {0} and {1}, and got value {2}.",
                lowerLimit, upperLimit, val);
            logger.Info(sb.ToString());

            bool tickCountIsInsideRange = lowerLimit <= val && val <= upperLimit;

            Skip.IfNot(tickCountIsInsideRange, string.Format("AssertIsInRange: {0}  -- WHICH IS OUTSIDE RANGE.", sb));
        }
 /// <summary>
 /// Returns a new <see cref="IJournal"/>, initialized with the provided <paramref name="actor"/>.
 /// </summary>
 /// <param name="actor">
 /// The actor.
 /// </param>
 /// <returns>
 /// A new <see cref="IJournal"/>, initialized for the provided <paramref name="actor"/>.
 /// </returns>
 public Task<IJournal> Create(IGrain actor)
 {
     var id = actor.GetIdString();
     var journal = Journal.GetOrAdd(id, _ => new InMemoryJournal());
     return Task.FromResult<IJournal>(journal);
 }
Esempio n. 41
0
 /// <summary>
 /// Returns runtime identity of the given grain
 /// </summary>
 /// <param name="grain">Runtime grain instance</param>
 /// <returns>Id assigned to the grain</returns>
 public static string Of(IGrain grain)
 {
     string id;
     grain.GetPrimaryKeyLong(out id);
     return id;
 }