You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rocketmq.apache.org by li...@apache.org on 2022/02/15 03:30:00 UTC

[rocketmq-client-csharp] branch develop updated: Setup infra for application layer development (#1)

This is an automated email from the ASF dual-hosted git repository.

lizhanhui pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/rocketmq-client-csharp.git


The following commit(s) were added to refs/heads/develop by this push:
     new f94a0be  Setup infra for application layer development (#1)
f94a0be is described below

commit f94a0befbd40321c765e850ebee1ea4ea42b0a7b
Author: Zhanhui Li <li...@apache.org>
AuthorDate: Tue Feb 15 11:29:56 2022 +0800

    Setup infra for application layer development (#1)
    
    Setup basic nuts and bolts
---
 .gitignore                                         |   3 +-
 examples/Program.cs                                |  49 ++++++
 rocketmq-client-csharp/{Class1.cs => Address.cs}   |  59 ++++---
 .../{Class1.cs => AddressScheme.cs}                |  47 +++---
 rocketmq-client-csharp/Broker.cs                   |  68 ++++++++
 rocketmq-client-csharp/ClientConfig.cs             | 123 ++++++++++++++
 rocketmq-client-csharp/ClientManager.cs            | 120 +++++++++++++
 rocketmq-client-csharp/Credentials.cs              |  65 +++++++
 .../{Class1.cs => IClientConfig.cs}                |  65 ++++---
 .../{Class1.cs => IClientManager.cs}               |  54 +++---
 .../{Class1.cs => ICredentialsProvider.cs}         |  45 +++--
 .../{Class1.cs => IRpcClient.cs}                   |   9 +-
 rocketmq-client-csharp/MetadataConstants.cs        |  37 ++++
 rocketmq-client-csharp/Partition.cs                |  85 ++++++++++
 .../{Class1.cs => Permission.cs}                   |  47 +++---
 .../Protos/apache/rocketmq/v1/service.proto        |  24 +--
 .../Protos/google/rpc/code.proto                   | 186 +++++++++++++++++++++
 rocketmq-client-csharp/{Class1.cs => RpcClient.cs} |  64 ++++---
 .../{Class1.cs => SendResult.cs}                   |  65 ++++---
 .../{Class1.cs => SendStatus.cs}                   |  49 +++---
 .../{Class1.cs => ServiceAddress.cs}               |  63 ++++---
 rocketmq-client-csharp/Signature.cs                |  67 ++++++++
 .../{Class1.cs => StaticCredentialsProvider.cs}    |  56 ++++---
 rocketmq-client-csharp/Topic.cs                    |  66 ++++++++
 rocketmq-client-csharp/TopicRouteData.cs           |  56 +++++++
 .../rocketmq-client-csharp.csproj                  |   3 +-
 .../Class1.cs => tests/BrokerTest.cs               |  62 ++++---
 .../Class1.cs => tests/ClientConfigTest.cs         |  55 +++---
 .../Class1.cs => tests/DateTimeTest.cs             |  58 ++++---
 .../Class1.cs => tests/SendResultTest.cs           |  68 +++++---
 tests/SignatureTest.cs                             |  48 ++++++
 .../StaticCredentialsProviderTest.cs               |  61 ++++---
 tests/TopicTest.cs                                 |  48 ++++++
 tests/UnitTest1.cs                                 |  39 ++++-
 tests/tests.csproj                                 |   1 +
 35 files changed, 1614 insertions(+), 401 deletions(-)

diff --git a/.gitignore b/.gitignore
index 8d4a6c0..4f19896 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 bin
-obj
\ No newline at end of file
+obj
+.vscode
\ No newline at end of file
diff --git a/examples/Program.cs b/examples/Program.cs
index 9d460cf..9bf745c 100644
--- a/examples/Program.cs
+++ b/examples/Program.cs
@@ -1,12 +1,61 @@
 using System;
+using System.Threading.Tasks;
+using System.Threading;
 
 namespace examples
 {
+
+    class Foo {
+        public int bar = 1;
+    }
     class Program
     {
+
+        static void RT(Action action, int seconds, CancellationToken token) {
+            if (null == action) {
+                return;
+            }
+
+            Task.Run(async () =>
+            {
+                while(!token.IsCancellationRequested) {
+                    action();
+                    await Task.Delay(TimeSpan.FromSeconds(seconds), token);
+                }
+            });
+        }
+
         static void Main(string[] args)
         {
             Console.WriteLine("Hello World!");
+
+            string accessKey = "key";
+            string accessSecret = "secret";
+            var credentials = new org.apache.rocketmq.StaticCredentialsProvider(accessKey, accessSecret).getCredentials();
+            bool expired = credentials.expired();
+
+            int workerThreads;
+            int completionPortThreads;
+            ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
+            Console.WriteLine($"Max: workerThread={workerThreads}, completionPortThreads={completionPortThreads}");
+            ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads);
+            Console.WriteLine($"Min: workerThread={workerThreads}, completionPortThreads={completionPortThreads}");
+
+            ThreadPool.QueueUserWorkItem((Object stateInfo) =>
+            {
+                Console.WriteLine("From ThreadPool");
+                if (stateInfo is Foo) {
+                    Console.WriteLine("Foo: bar=" + (stateInfo as Foo).bar);
+                }
+            }, new Foo());
+
+            var cts = new CancellationTokenSource();
+            RT(() =>
+            {
+                Console.WriteLine("Hello Again" + Thread.CurrentThread.Name);
+            }, 1, cts.Token);
+            cts.CancelAfter(3000);
+            Console.ReadKey();
         }
     }
 }
diff --git a/rocketmq-client-csharp/Class1.cs b/rocketmq-client-csharp/Address.cs
similarity index 68%
copy from rocketmq-client-csharp/Class1.cs
copy to rocketmq-client-csharp/Address.cs
index f98588c..dadf346 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/rocketmq-client-csharp/Address.cs
@@ -1,24 +1,35 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace org.apache.rocketmq {
+    public class Address {
+        public Address(string host, int port) {
+            this.host = host;
+            this.port = port;
+        }
+
+        private string host;
+        public string Host {
+            get { return host; }
+        }
+
+        private int port;
+        public int Port {
+            get { return port; }
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Class1.cs b/rocketmq-client-csharp/AddressScheme.cs
similarity index 87%
copy from rocketmq-client-csharp/Class1.cs
copy to rocketmq-client-csharp/AddressScheme.cs
index f98588c..3e95b09 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/rocketmq-client-csharp/AddressScheme.cs
@@ -1,24 +1,23 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace org.apache.rocketmq {
+    public enum AddressScheme {
+        IPv4,
+        IPv6,
+        DOMAIN_NAME,
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Broker.cs b/rocketmq-client-csharp/Broker.cs
new file mode 100644
index 0000000..e909bf7
--- /dev/null
+++ b/rocketmq-client-csharp/Broker.cs
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace org.apache.rocketmq {
+    public class Broker : IComparable<Broker>, IEquatable<Broker> {
+
+        public Broker(string name, int id, ServiceAddress address) {
+            this.name = name;
+            this.id = id;
+            this.address = address;
+        }
+
+        private string name;
+        public string Name {
+            get { return name; }
+        }
+
+        private int id;
+        public int Id {
+            get { return id; }
+        }
+
+        private ServiceAddress address;
+        public ServiceAddress Address {
+            get { return address; }
+        }
+
+        public int CompareTo(Broker other) {
+            if (0 != name.CompareTo(other.name)) {
+                return name.CompareTo(other.name);
+            }
+
+            return id.CompareTo(other.id);
+        }
+
+        public bool Equals(Broker other) {
+            return name.Equals(other.name) && id.Equals(other.id);
+        }
+
+        public override bool Equals(Object other) {
+            if (!(other is Broker)) {
+                return false;
+            }
+            return Equals(other as Broker);
+        }
+
+        public override int GetHashCode()
+        {
+            return HashCode.Combine(name, id);
+        }
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/ClientConfig.cs b/rocketmq-client-csharp/ClientConfig.cs
new file mode 100644
index 0000000..3f27713
--- /dev/null
+++ b/rocketmq-client-csharp/ClientConfig.cs
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+
+namespace org.apache.rocketmq {
+
+    public class ClientConfig : IClientConfig {
+
+        public ClientConfig() {
+            var hostName = System.Net.Dns.GetHostName();
+            var pid = System.Diagnostics.Process.GetCurrentProcess().Id;
+            clientId_ = string.Format("{0}@{1}#{2}", hostName, pid, instanceName_);
+        }
+
+        public string region() {
+            return region_;
+        }
+        public string Region {
+            set { region_ = value; }
+        }
+
+        public string serviceName() {
+            return serviceName_;
+        }
+        public string ServiceName {
+            set { serviceName_ = value; }
+        }
+
+        public string resourceNamespace() {
+            return resourceNamespace_;
+        }
+        public string ResourceNamespace {
+            set { resourceNamespace_ = value; }
+        }
+
+        public ICredentialsProvider credentialsProvider() {
+            return credentialsProvider_;
+        }
+        
+        public ICredentialsProvider CredentialsProvider {
+            set { credentialsProvider_ = value; }
+        }
+
+        public string tenantId() {
+            return tenantId_;
+        }
+        public string TenantId {
+            set { tenantId_ = value; }
+        }
+
+        public TimeSpan getIoTimeout() {
+            return ioTimeout_;
+        }
+        public TimeSpan IoTimeout {
+            set { ioTimeout_ = value; }
+        }
+
+        public TimeSpan getLongPollingTimeout() {
+            return longPollingIoTimeout_;
+        }
+        public TimeSpan LongPollingTimeout {
+            set { longPollingIoTimeout_ = value; }
+        }
+
+        public string getGroupName() {
+            return groupName_;
+        }
+        public string GroupName {
+            set { groupName_ = value; }
+        }
+
+        public string clientId() {
+            return clientId_;
+        }
+
+        public bool isTracingEnabled() {
+            return tracingEnabled_;
+        }
+        public bool TracingEnabled {
+            set { tracingEnabled_ = value; }
+        }
+
+        public void setInstanceName(string instanceName) {
+            this.instanceName_ = instanceName;
+        }
+
+        private string region_ = "cn-hangzhou";
+        private string serviceName_ = "ONS";
+
+        private string resourceNamespace_;
+
+        private ICredentialsProvider credentialsProvider_;
+
+        private string tenantId_;
+
+        private TimeSpan ioTimeout_;
+
+        private TimeSpan longPollingIoTimeout_;
+
+        private string groupName_;
+
+        private string clientId_;
+
+        private bool tracingEnabled_ = false;
+
+        private string instanceName_ = "default";
+    }
+
+}
diff --git a/rocketmq-client-csharp/ClientManager.cs b/rocketmq-client-csharp/ClientManager.cs
new file mode 100644
index 0000000..4dd8790
--- /dev/null
+++ b/rocketmq-client-csharp/ClientManager.cs
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.Collections.Concurrent;
+
+using rmq = global::apache.rocketmq.v1;
+using Grpc.Net.Client;
+using System;
+using System.Threading.Tasks;
+using grpc = global::Grpc.Core;
+using System.Collections.Generic;
+
+namespace org.apache.rocketmq {
+    public class ClientManager : IClientManager {
+
+        public ClientManager() {
+            rpcClients = new ConcurrentDictionary<string, RpcClient>();
+        }
+
+        public IRpcClient getRpcClient(string target) {
+            if (!rpcClients.ContainsKey(target)) {
+                using var channel = GrpcChannel.ForAddress(target);
+                var client = new rmq.MessagingService.MessagingServiceClient(channel);
+                var rpcClient = new RpcClient(client);
+                if(rpcClients.TryAdd(target, rpcClient)) {
+                    return rpcClient;
+                }
+            }
+            return rpcClients[target];
+        }
+
+        public async Task<TopicRouteData> resolveRoute(string target, grpc::Metadata metadata, rmq.QueryRouteRequest request, TimeSpan timeout) {
+            var rpcClient = getRpcClient(target);
+            var callOptions = new grpc::CallOptions();
+            callOptions.WithDeadline(DateTime.Now.Add(timeout))
+                .WithHeaders(metadata);
+            var queryRouteResponse = await rpcClient.queryRoute(request, callOptions);
+
+            if (queryRouteResponse.Common.Status.Code != ((int)Google.Rpc.Code.Ok)) {
+                // Raise an application layer exception
+
+            }
+
+            var partitions = new List<Partition>();
+            // Translate protobuf object to domain specific one
+            foreach (var partition in queryRouteResponse.Partitions)
+            {
+                var topic = new Topic(partition.Topic.ResourceNamespace, partition.Topic.Name);
+                var id = partition.Id;
+                Permission permission = Permission.READ_WRITE;
+                switch (partition.Permission) {
+                    case rmq.Permission.None:
+                    {
+                        permission = Permission.NONE;
+                        break;
+                    }
+                    case rmq.Permission.Read:
+                    {
+                        permission = Permission.READ;
+                        break;
+                    }
+                    case rmq.Permission.Write:
+                    {
+                        permission = Permission.WRITE;
+                        break;
+                    }
+                    case rmq.Permission.ReadWrite:
+                    {
+                        permission = Permission.READ_WRITE;
+                        break;
+                    }
+                }
+
+                AddressScheme scheme = AddressScheme.IPv4;
+                switch(partition.Broker.Endpoints.Scheme) {
+                    case rmq.AddressScheme.Ipv4: {
+                        scheme = AddressScheme.IPv4;
+                        break;
+                    }
+                    case rmq.AddressScheme.Ipv6: {
+                        scheme = AddressScheme.IPv6;
+                        break;
+                    }
+                    case rmq.AddressScheme.DomainName: {
+                        scheme = AddressScheme.DOMAIN_NAME;
+                        break;
+                    }
+                }
+
+                List<Address> addresses = new List<Address>();
+                foreach(var item in partition.Broker.Endpoints.Addresses) {
+                    addresses.Add(new Address(item.Host, item.Port));
+                }
+                ServiceAddress serviceAddress = new ServiceAddress(scheme, addresses);
+                Broker broker = new Broker(partition.Broker.Name, id, serviceAddress);
+                partitions.Add(new Partition(topic, broker, id, permission));
+            }
+
+            var topicRouteData = new TopicRouteData(partitions);
+            return topicRouteData;
+        }
+
+        private ConcurrentDictionary<string, RpcClient> rpcClients;
+
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Credentials.cs b/rocketmq-client-csharp/Credentials.cs
new file mode 100644
index 0000000..2da9581
--- /dev/null
+++ b/rocketmq-client-csharp/Credentials.cs
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace org.apache.rocketmq {
+    public class Credentials {
+
+        public Credentials(string accessKey, string accessSecret) {
+            this.accessKey = accessKey;
+            this.accessSecret = accessSecret;
+        }
+
+        public Credentials(string accessKey, string accessSecret, string sessionToken, DateTime expirationInstant) {
+            this.accessKey = accessKey;
+            this.accessSecret = accessSecret;
+            this.sessionToken = sessionToken;
+            this.expirationInstant = expirationInstant;
+        }
+
+        public bool empty() {
+            return String.IsNullOrEmpty(accessKey) || String.IsNullOrEmpty(accessSecret);
+        }
+
+        public bool expired() {
+            if (DateTime.MinValue == expirationInstant) {
+                return false;
+            }
+
+            return DateTime.Now > expirationInstant;
+        }
+
+        private string accessKey;
+        public string AccessKey {
+            get { return accessKey; }
+        }
+        
+        private string accessSecret;
+        public string AccessSecret {
+            get { return accessSecret; }
+        }
+
+        private string sessionToken;
+        public string SessionToken {
+            get { return sessionToken; }
+        }
+
+        private DateTime expirationInstant = DateTime.MinValue;
+
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Class1.cs b/rocketmq-client-csharp/IClientConfig.cs
similarity index 66%
copy from rocketmq-client-csharp/Class1.cs
copy to rocketmq-client-csharp/IClientConfig.cs
index f98588c..b83006c 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/rocketmq-client-csharp/IClientConfig.cs
@@ -1,24 +1,41 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+
+namespace org.apache.rocketmq {
+    public interface IClientConfig {
+        string region();
+
+        string serviceName();
+
+        string resourceNamespace();
+
+        ICredentialsProvider credentialsProvider();
+
+        string tenantId();
+
+        TimeSpan getIoTimeout();
+
+        TimeSpan getLongPollingTimeout();
+
+        string getGroupName();
+
+        string clientId();
+
+        bool isTracingEnabled();
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Class1.cs b/rocketmq-client-csharp/IClientManager.cs
similarity index 70%
copy from rocketmq-client-csharp/Class1.cs
copy to rocketmq-client-csharp/IClientManager.cs
index f98588c..ea8ba55 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/rocketmq-client-csharp/IClientManager.cs
@@ -1,24 +1,30 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using apache.rocketmq.v1;
+using System.Threading.Tasks;
+using System;
+using grpc = global::Grpc.Core;
+
+namespace org.apache.rocketmq {
+    public interface IClientManager {
+        IRpcClient getRpcClient(string target);
+
+        Task<TopicRouteData> resolveRoute(string target, grpc::Metadata metadata, QueryRouteRequest request, TimeSpan timeout);
+
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Class1.cs b/rocketmq-client-csharp/ICredentialsProvider.cs
similarity index 87%
copy from rocketmq-client-csharp/Class1.cs
copy to rocketmq-client-csharp/ICredentialsProvider.cs
index f98588c..6e7112e 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/rocketmq-client-csharp/ICredentialsProvider.cs
@@ -1,24 +1,21 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace org.apache.rocketmq {
+    public interface ICredentialsProvider {
+        Credentials getCredentials();
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Class1.cs b/rocketmq-client-csharp/IRpcClient.cs
similarity index 74%
copy from rocketmq-client-csharp/Class1.cs
copy to rocketmq-client-csharp/IRpcClient.cs
index f98588c..d4102b8 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/rocketmq-client-csharp/IRpcClient.cs
@@ -15,10 +15,15 @@
  * limitations under the License.
  */
 using System;
+using System.Threading.Tasks;
+using apache.rocketmq.v1;
+using grpc = global::Grpc.Core;
 
-namespace rocketmq_client_csharp
+namespace org.apache.rocketmq
 {
-    public class Class1
+    public interface IRpcClient
     {
+     Task<QueryRouteResponse> queryRoute(QueryRouteRequest request, grpc::CallOptions callOptions);
+
     }
 }
diff --git a/rocketmq-client-csharp/MetadataConstants.cs b/rocketmq-client-csharp/MetadataConstants.cs
new file mode 100644
index 0000000..184bec8
--- /dev/null
+++ b/rocketmq-client-csharp/MetadataConstants.cs
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace org.apache.rocketmq {
+    public class MetadataConstants {
+        public const string TENANT_ID_KEY = "x-mq-tenant-id";
+        public const string NAMESPACE_KEY = "x-mq-namespace";
+        public const string AUTHORIZATION = "authorization";
+        public const string STS_SESSION_TOKEN = "x-mq-session-token";
+        public const string DATE_TIME_KEY = "x-mq-date-time";
+        public const string ALGORITHM_KEY = "MQv2-HMAC-SHA1";
+        public const string CREDENTIAL_KEY = "Credential";
+        public const string SIGNED_HEADERS_KEY = "SignedHeaders";
+        public const string SIGNATURE_KEY = "Signature";
+        public const string DATE_TIME_FORMAT = "yyyyMMddTHHmmssZ";
+        public const string LANGUAGE_KEY = "x-mq-language";
+        public const string CLIENT_VERSION_KEY = "x-mq-client-version";
+        public const string PROTOCOL_VERSION_KEY = "x-mq-protocol-version";
+        public const string REQUEST_ID_KEY = "x-mq-request-id";
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Partition.cs b/rocketmq-client-csharp/Partition.cs
new file mode 100644
index 0000000..410601e
--- /dev/null
+++ b/rocketmq-client-csharp/Partition.cs
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+
+namespace org.apache.rocketmq {
+    
+    public class Partition : IEquatable<Partition>, IComparable<Partition> {
+
+        public Partition(Topic topic, Broker broker, int id, Permission permission) {
+            this.topic = topic;
+            this.broker = broker;
+            this.id = id;
+            this.permission = permission;
+        }
+
+        private Topic topic;
+        public Topic Topic{
+            get { return topic; }
+        }
+
+        private Broker broker;
+        public Broker Broker {
+            get { return broker; }
+        }
+
+        private int id;
+        public int Id {
+            get { return id; }
+        }
+
+        Permission permission;
+        public Permission Permission {
+            get { return permission; }
+        }
+
+        public bool Equals(Partition other) {
+            return topic.Equals(other.topic) 
+                && broker.Equals(other.broker) 
+                && id.Equals(other.id) 
+                && permission == other.permission;
+        }
+
+        public override bool Equals(Object other) {
+            if (!(other is Partition)) {
+                return false;
+            }
+            return Equals(other);
+        }
+
+        public override int GetHashCode()
+        {
+            return HashCode.Combine(topic, broker, id, permission);
+        }
+
+        public int CompareTo(Partition other) {
+            if (0 != topic.CompareTo(other.topic)) {
+                return topic.CompareTo(other.topic);
+            }
+
+            if (0 != broker.CompareTo(other.broker)) {
+                return broker.CompareTo(other.broker);
+            }
+
+            if (0 != id.CompareTo(other.id)) {
+                return id.CompareTo(other.id);
+            }
+
+            return permission.CompareTo(other.permission);
+        }
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Class1.cs b/rocketmq-client-csharp/Permission.cs
similarity index 87%
copy from rocketmq-client-csharp/Class1.cs
copy to rocketmq-client-csharp/Permission.cs
index f98588c..659c15b 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/rocketmq-client-csharp/Permission.cs
@@ -1,24 +1,23 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public enum Permission {
+    NONE,
+    READ,
+    WRITE,
+    READ_WRITE,
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Protos/apache/rocketmq/v1/service.proto b/rocketmq-client-csharp/Protos/apache/rocketmq/v1/service.proto
index 2dacfa8..6f1b4c1 100644
--- a/rocketmq-client-csharp/Protos/apache/rocketmq/v1/service.proto
+++ b/rocketmq-client-csharp/Protos/apache/rocketmq/v1/service.proto
@@ -386,13 +386,13 @@ message NotifyClientTerminationResponse {
 // errors raise, return a response with common.status.code == `INTERNAL`.
 service MessagingService {
 
-  // Querys the route entries of the requested topic in the perspective of the
+  // Queries the route entries of the requested topic in the perspective of the
   // given endpoints. On success, servers should return a collection of
   // addressable partitions. Note servers may return customized route entries
   // based on endpoints provided.
   //
   // If the requested topic doesn't exist, returns `NOT_FOUND`.
-  // If the specific endpoints is emtpy, returns `INVALID_ARGUMENT`.
+  // If the specific endpoints is empty, returns `INVALID_ARGUMENT`.
   rpc QueryRoute(QueryRouteRequest) returns (QueryRouteResponse) {}
 
   // Producer or consumer sends HeartbeatRequest to servers periodically to
@@ -425,17 +425,17 @@ service MessagingService {
   // If the destination topic doesn't exist, returns `NOT_FOUND`.
   rpc SendMessage(SendMessageRequest) returns (SendMessageResponse) {}
 
-  // Querys the assigned partition route info of a topic for current consumer,
-  // the returned assignment result is descided by server-side load balacner.
+  // Queries the assigned partition route info of a topic for current consumer,
+  // the returned assignment result is decided by server-side load balancer.
   //
   // If the corresponding topic doesn't exist, returns `NOT_FOUND`.
-  // If the specific endpoints is emtpy, returns `INVALID_ARGUMENT`.
+  // If the specific endpoints is empty, returns `INVALID_ARGUMENT`.
   rpc QueryAssignment(QueryAssignmentRequest)
       returns (QueryAssignmentResponse) {}
 
-  // Receives messages from the server in batch manner, returns a set of
-  // messages if success. The received messages should be acked or uacked after
-  // processed.
+  // Receives messages from the server in batch manner, returns a batch of
+  // messages if success. The received messages should be ACKed or NACKed after
+  // processing.
   //
   // If the pending concurrent receive requests exceed the quota of the given
   // consumer group, returns `UNAVAILABLE`. If the upstream store server hangs,
@@ -470,14 +470,14 @@ service MessagingService {
   // Commits or rollback one transactional message.
   rpc EndTransaction(EndTransactionRequest) returns (EndTransactionResponse) {}
 
-  // Querys the offset of the specific partition, returns the offset with `OK`
+  // Queries the offset of the specific partition, returns the offset with `OK`
   // if success. The message server should maintain a numerical offset for each
-  // message in a parition.
+  // message in a partition.
   rpc QueryOffset(QueryOffsetRequest) returns (QueryOffsetResponse) {}
 
   // Pulls messages from the specific partition, returns a set of messages with
-  // next pull offset. The pulled messages can't be acked or nacked, while the
-  // client is responsible for manage offesets for consumer, typically update
+  // next pull offset. The pulled messages can't be ACKed or NACKed, while the
+  // client is responsible for manage offsets for consumer, typically update
   // consume offset to local memory or a third-party storage service.
   //
   // If the pending concurrent receive requests exceed the quota of the given
diff --git a/rocketmq-client-csharp/Protos/google/rpc/code.proto b/rocketmq-client-csharp/Protos/google/rpc/code.proto
new file mode 100644
index 0000000..98ae0ac
--- /dev/null
+++ b/rocketmq-client-csharp/Protos/google/rpc/code.proto
@@ -0,0 +1,186 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package google.rpc;
+
+option go_package = "google.golang.org/genproto/googleapis/rpc/code;code";
+option java_multiple_files = true;
+option java_outer_classname = "CodeProto";
+option java_package = "com.google.rpc";
+option objc_class_prefix = "RPC";
+
+// The canonical error codes for gRPC APIs.
+//
+//
+// Sometimes multiple error codes may apply.  Services should return
+// the most specific error code that applies.  For example, prefer
+// `OUT_OF_RANGE` over `FAILED_PRECONDITION` if both codes apply.
+// Similarly prefer `NOT_FOUND` or `ALREADY_EXISTS` over `FAILED_PRECONDITION`.
+enum Code {
+  // Not an error; returned on success
+  //
+  // HTTP Mapping: 200 OK
+  OK = 0;
+
+  // The operation was cancelled, typically by the caller.
+  //
+  // HTTP Mapping: 499 Client Closed Request
+  CANCELLED = 1;
+
+  // Unknown error.  For example, this error may be returned when
+  // a `Status` value received from another address space belongs to
+  // an error space that is not known in this address space.  Also
+  // errors raised by APIs that do not return enough error information
+  // may be converted to this error.
+  //
+  // HTTP Mapping: 500 Internal Server Error
+  UNKNOWN = 2;
+
+  // The client specified an invalid argument.  Note that this differs
+  // from `FAILED_PRECONDITION`.  `INVALID_ARGUMENT` indicates arguments
+  // that are problematic regardless of the state of the system
+  // (e.g., a malformed file name).
+  //
+  // HTTP Mapping: 400 Bad Request
+  INVALID_ARGUMENT = 3;
+
+  // The deadline expired before the operation could complete. For operations
+  // that change the state of the system, this error may be returned
+  // even if the operation has completed successfully.  For example, a
+  // successful response from a server could have been delayed long
+  // enough for the deadline to expire.
+  //
+  // HTTP Mapping: 504 Gateway Timeout
+  DEADLINE_EXCEEDED = 4;
+
+  // Some requested entity (e.g., file or directory) was not found.
+  //
+  // Note to server developers: if a request is denied for an entire class
+  // of users, such as gradual feature rollout or undocumented whitelist,
+  // `NOT_FOUND` may be used. If a request is denied for some users within
+  // a class of users, such as user-based access control, `PERMISSION_DENIED`
+  // must be used.
+  //
+  // HTTP Mapping: 404 Not Found
+  NOT_FOUND = 5;
+
+  // The entity that a client attempted to create (e.g., file or directory)
+  // already exists.
+  //
+  // HTTP Mapping: 409 Conflict
+  ALREADY_EXISTS = 6;
+
+  // The caller does not have permission to execute the specified
+  // operation. `PERMISSION_DENIED` must not be used for rejections
+  // caused by exhausting some resource (use `RESOURCE_EXHAUSTED`
+  // instead for those errors). `PERMISSION_DENIED` must not be
+  // used if the caller can not be identified (use `UNAUTHENTICATED`
+  // instead for those errors). This error code does not imply the
+  // request is valid or the requested entity exists or satisfies
+  // other pre-conditions.
+  //
+  // HTTP Mapping: 403 Forbidden
+  PERMISSION_DENIED = 7;
+
+  // The request does not have valid authentication credentials for the
+  // operation.
+  //
+  // HTTP Mapping: 401 Unauthorized
+  UNAUTHENTICATED = 16;
+
+  // Some resource has been exhausted, perhaps a per-user quota, or
+  // perhaps the entire file system is out of space.
+  //
+  // HTTP Mapping: 429 Too Many Requests
+  RESOURCE_EXHAUSTED = 8;
+
+  // The operation was rejected because the system is not in a state
+  // required for the operation's execution.  For example, the directory
+  // to be deleted is non-empty, an rmdir operation is applied to
+  // a non-directory, etc.
+  //
+  // Service implementors can use the following guidelines to decide
+  // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`:
+  //  (a) Use `UNAVAILABLE` if the client can retry just the failing call.
+  //  (b) Use `ABORTED` if the client should retry at a higher level
+  //      (e.g., when a client-specified test-and-set fails, indicating the
+  //      client should restart a read-modify-write sequence).
+  //  (c) Use `FAILED_PRECONDITION` if the client should not retry until
+  //      the system state has been explicitly fixed.  E.g., if an "rmdir"
+  //      fails because the directory is non-empty, `FAILED_PRECONDITION`
+  //      should be returned since the client should not retry unless
+  //      the files are deleted from the directory.
+  //
+  // HTTP Mapping: 400 Bad Request
+  FAILED_PRECONDITION = 9;
+
+  // The operation was aborted, typically due to a concurrency issue such as
+  // a sequencer check failure or transaction abort.
+  //
+  // See the guidelines above for deciding between `FAILED_PRECONDITION`,
+  // `ABORTED`, and `UNAVAILABLE`.
+  //
+  // HTTP Mapping: 409 Conflict
+  ABORTED = 10;
+
+  // The operation was attempted past the valid range.  E.g., seeking or
+  // reading past end-of-file.
+  //
+  // Unlike `INVALID_ARGUMENT`, this error indicates a problem that may
+  // be fixed if the system state changes. For example, a 32-bit file
+  // system will generate `INVALID_ARGUMENT` if asked to read at an
+  // offset that is not in the range [0,2^32-1], but it will generate
+  // `OUT_OF_RANGE` if asked to read from an offset past the current
+  // file size.
+  //
+  // There is a fair bit of overlap between `FAILED_PRECONDITION` and
+  // `OUT_OF_RANGE`.  We recommend using `OUT_OF_RANGE` (the more specific
+  // error) when it applies so that callers who are iterating through
+  // a space can easily look for an `OUT_OF_RANGE` error to detect when
+  // they are done.
+  //
+  // HTTP Mapping: 400 Bad Request
+  OUT_OF_RANGE = 11;
+
+  // The operation is not implemented or is not supported/enabled in this
+  // service.
+  //
+  // HTTP Mapping: 501 Not Implemented
+  UNIMPLEMENTED = 12;
+
+  // Internal errors.  This means that some invariants expected by the
+  // underlying system have been broken.  This error code is reserved
+  // for serious errors.
+  //
+  // HTTP Mapping: 500 Internal Server Error
+  INTERNAL = 13;
+
+  // The service is currently unavailable.  This is most likely a
+  // transient condition, which can be corrected by retrying with
+  // a backoff. Note that it is not always safe to retry
+  // non-idempotent operations.
+  //
+  // See the guidelines above for deciding between `FAILED_PRECONDITION`,
+  // `ABORTED`, and `UNAVAILABLE`.
+  //
+  // HTTP Mapping: 503 Service Unavailable
+  UNAVAILABLE = 14;
+
+  // Unrecoverable data loss or corruption.
+  //
+  // HTTP Mapping: 500 Internal Server Error
+  DATA_LOSS = 15;
+}
diff --git a/rocketmq-client-csharp/Class1.cs b/rocketmq-client-csharp/RpcClient.cs
similarity index 50%
copy from rocketmq-client-csharp/Class1.cs
copy to rocketmq-client-csharp/RpcClient.cs
index f98588c..0cc8354 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/rocketmq-client-csharp/RpcClient.cs
@@ -1,24 +1,40 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.Threading.Tasks;
+using apache.rocketmq.v1;
+using grpc = global::Grpc.Core;
+
+namespace org.apache.rocketmq {
+    public class RpcClient : IRpcClient {
+        public RpcClient(MessagingService.MessagingServiceClient client) {
+            stub = client;
+        }
+
+        public async Task<QueryRouteResponse> queryRoute(QueryRouteRequest request, grpc::CallOptions callOptions) {
+            var call = stub.QueryRouteAsync(request, callOptions);
+            var response = await call.ResponseAsync;
+            var status = call.GetStatus();
+            if (status.StatusCode != grpc.StatusCode.OK) {
+                //TODO: Something is wrong, raise an exception here.
+            }
+            return response;
+        }
+
+        private MessagingService.MessagingServiceClient stub;
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Class1.cs b/rocketmq-client-csharp/SendResult.cs
similarity index 57%
copy from rocketmq-client-csharp/Class1.cs
copy to rocketmq-client-csharp/SendResult.cs
index f98588c..5967cca 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/rocketmq-client-csharp/SendResult.cs
@@ -1,24 +1,41 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace org.apache.rocketmq {
+    public sealed class SendResult {
+        public SendResult(string messageId) {
+            status_ = SendStatus.SEND_OK;
+            messageId_ = messageId;
+        }
+
+        public SendResult(string messageId, SendStatus status) {
+            status_ = status;
+            messageId_ = messageId;
+        }
+
+        private string messageId_;
+
+        public string MessageId {
+            get { return messageId_; }
+        }
+
+
+        private SendStatus status_;
+        public SendStatus Status {
+            get { return status_; }
+        }
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Class1.cs b/rocketmq-client-csharp/SendStatus.cs
similarity index 82%
copy from rocketmq-client-csharp/Class1.cs
copy to rocketmq-client-csharp/SendStatus.cs
index f98588c..8964211 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/rocketmq-client-csharp/SendStatus.cs
@@ -1,24 +1,25 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace org.apache.rocketmq {
+    public enum SendStatus {
+        SEND_OK,
+        FLUSH_DISK_TIMEOUT,
+        FLUSH_SLAVE_TIMEOUT,
+        SLAVE_NOT_AVAILABLE,
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Class1.cs b/rocketmq-client-csharp/ServiceAddress.cs
similarity index 60%
copy from rocketmq-client-csharp/Class1.cs
copy to rocketmq-client-csharp/ServiceAddress.cs
index f98588c..4aab213 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/rocketmq-client-csharp/ServiceAddress.cs
@@ -1,24 +1,39 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.Collections.Generic;
+
+namespace org.apache.rocketmq {
+    public sealed class ServiceAddress {
+
+        public ServiceAddress(AddressScheme scheme, List<Address> addresses) {
+            this.scheme = scheme;
+            this.addresses = addresses;
+        }
+
+        private AddressScheme scheme;
+        public AddressScheme Scheme {
+            get { return scheme; }
+        }
+
+        private List<Address> addresses;
+        public List<Address> Addresses{
+            get { return addresses; }
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Signature.cs b/rocketmq-client-csharp/Signature.cs
new file mode 100644
index 0000000..4f1fd93
--- /dev/null
+++ b/rocketmq-client-csharp/Signature.cs
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.Text;
+using grpc = global::Grpc.Core;
+using System.Security.Cryptography;
+
+namespace org.apache.rocketmq {
+    public class Signature {
+        public static void sign(IClientConfig clientConfig, grpc::Metadata metadata) {
+            metadata.Add(MetadataConstants.LANGUAGE_KEY, "C#");
+            metadata.Add(MetadataConstants.CLIENT_VERSION_KEY, "5.0.0");
+            if (!String.IsNullOrEmpty(clientConfig.tenantId())) {
+                metadata.Add(MetadataConstants.TENANT_ID_KEY, clientConfig.tenantId());
+            }
+
+            if (!String.IsNullOrEmpty(clientConfig.resourceNamespace())) {
+                metadata.Add(MetadataConstants.NAMESPACE_KEY, clientConfig.resourceNamespace());
+            }
+
+            string time = DateTime.Now.ToString(MetadataConstants.DATE_TIME_FORMAT);
+            metadata.Add(MetadataConstants.DATE_TIME_KEY, time);
+
+            if (null != clientConfig.credentialsProvider()) {
+                var credentials = clientConfig.credentialsProvider().getCredentials();
+                if (null == credentials || credentials.expired()) {
+                    return;
+                }
+
+                if (!String.IsNullOrEmpty(credentials.SessionToken)) {
+                    metadata.Add(MetadataConstants.STS_SESSION_TOKEN, credentials.SessionToken);
+                }
+
+                byte[] secretData = Encoding.ASCII.GetBytes(credentials.AccessSecret);
+                byte[] data = Encoding.ASCII.GetBytes(time);
+                HMACSHA1 signer = new HMACSHA1(secretData);
+                byte[] digest = signer.ComputeHash(data);
+                string hmac = BitConverter.ToString(digest).Replace("-", "");
+                string authorization = string.Format("{0} {1}={2}/{3}/{4}, {5}={6}, {7}={8}", 
+                    MetadataConstants.ALGORITHM_KEY,
+                    MetadataConstants.CREDENTIAL_KEY,
+                    credentials.AccessKey,
+                    clientConfig.region(),
+                    clientConfig.serviceName(),
+                    MetadataConstants.SIGNED_HEADERS_KEY,
+                    MetadataConstants.DATE_TIME_KEY,
+                    MetadataConstants.SIGNATURE_KEY,
+                    hmac);
+                metadata.Add(MetadataConstants.AUTHORIZATION, authorization);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Class1.cs b/rocketmq-client-csharp/StaticCredentialsProvider.cs
similarity index 63%
copy from rocketmq-client-csharp/Class1.cs
copy to rocketmq-client-csharp/StaticCredentialsProvider.cs
index f98588c..301613b 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/rocketmq-client-csharp/StaticCredentialsProvider.cs
@@ -1,24 +1,32 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace org.apache.rocketmq {
+    public class StaticCredentialsProvider : ICredentialsProvider {
+
+        public StaticCredentialsProvider(string accessKey, string accessSecret) {
+            this.accessKey = accessKey;
+            this.accessSecret = accessSecret;
+        }
+
+        public Credentials getCredentials() {
+            return new Credentials(accessKey, accessSecret);
+        }
+
+        private string accessKey;
+        private string accessSecret;
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Topic.cs b/rocketmq-client-csharp/Topic.cs
new file mode 100644
index 0000000..dcc7100
--- /dev/null
+++ b/rocketmq-client-csharp/Topic.cs
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace org.apache.rocketmq {
+    public class Topic : IComparable<Topic>, IEquatable<Topic> {
+        public Topic(string resource_namespace, string name) {
+            resourceNamespace = resource_namespace;
+            this.name = name;
+        }
+
+        private string resourceNamespace;
+        public string ResourceNamespace {
+            get { return resourceNamespace; }
+        }
+
+        private string name;
+        public string Name {
+            get { return name; }
+        }
+
+        public int CompareTo(Topic other) {
+            if (0 != resourceNamespace.CompareTo(other.resourceNamespace)) {
+                return resourceNamespace.CompareTo(other.resourceNamespace);
+            }
+
+            if (0 != name.CompareTo(other.name)) {
+                return name.CompareTo(other.name);
+            }
+
+            return 0;
+        }
+
+        public bool Equals(Topic other) {
+            return resourceNamespace.Equals(other.resourceNamespace) && name.Equals(other.name);
+        }
+
+        public override bool Equals(Object other) {
+            if (!(other is Topic)) {
+                return false;
+            }
+            return Equals(other as Topic);
+        }
+
+        public override int GetHashCode()
+        {
+            return HashCode.Combine(resourceNamespace, name);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/TopicRouteData.cs b/rocketmq-client-csharp/TopicRouteData.cs
new file mode 100644
index 0000000..a860669
--- /dev/null
+++ b/rocketmq-client-csharp/TopicRouteData.cs
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.Collections.Generic;
+
+namespace org.apache.rocketmq {
+
+    public class TopicRouteData : IEquatable<TopicRouteData> {
+
+        public TopicRouteData(List<Partition> partitions) {
+            this.partitions = partitions;
+            this.partitions.Sort();
+        }
+
+        private List<Partition> partitions;
+
+        public List<Partition> Partitions {
+            get { return partitions; }
+        }
+
+        public bool Equals(TopicRouteData other) {
+            return partitions.Equals(other.partitions);
+        }
+
+        public override bool Equals(object other)
+        {
+
+            if (!(other is TopicRouteData)) {
+                return false;
+            }
+
+            return Equals(other as TopicRouteData);
+        }
+
+        public override int GetHashCode()
+        {
+            return HashCode.Combine(partitions);
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/rocketmq-client-csharp.csproj b/rocketmq-client-csharp/rocketmq-client-csharp.csproj
index 0a1e2a6..eb8149c 100644
--- a/rocketmq-client-csharp/rocketmq-client-csharp.csproj
+++ b/rocketmq-client-csharp/rocketmq-client-csharp.csproj
@@ -19,8 +19,9 @@
     </PackageReference>
 
     <Protobuf Include="Protos\apache\rocketmq\v1\definition.proto" ProtoRoot="Protos" GrpcServices="Client" />
-    <Protobuf Include="Protos\google\rpc\status.proto" ProtoRoot="Protos" GrpcServices="Client" />
+    <Protobuf Include="Protos\google\rpc\code.proto" ProtoRoot="Protos" GrpcServices="Client" />
     <Protobuf Include="Protos\google\rpc\error_details.proto" ProtoRoot="Protos" GrpcServices="Client" />
+    <Protobuf Include="Protos\google\rpc\status.proto" ProtoRoot="Protos" GrpcServices="Client" />
     <Protobuf Include="Protos\apache\rocketmq\v1\service.proto" ProtoRoot="Protos" GrpcServices="Client">
       <Link>Protos\apache\rocketmq\v1\definition.proto</Link>
       <Link>Protos\google\rpc\status.proto</Link>
diff --git a/rocketmq-client-csharp/Class1.cs b/tests/BrokerTest.cs
similarity index 57%
copy from rocketmq-client-csharp/Class1.cs
copy to tests/BrokerTest.cs
index f98588c..8de89d5 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/tests/BrokerTest.cs
@@ -1,24 +1,38 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace org.apache.rocketmq {
+    [TestClass]
+    public class BrokerTest {
+
+        [TestMethod]
+        public void testCompareTo() {
+            var b1 = new Broker("b1", 0, null);
+            var b2 = new Broker("b1", 1, null);
+            Assert.AreEqual(b1.CompareTo(b2), -1);
+        }
+
+        [TestMethod]
+        public void testEquals() {
+            var b1 = new Broker("b1", 0, null);
+            var b2 = new Broker("b1", 0, null);
+            Assert.AreEqual(b1, b2, "Equals method should be employed to test equality");
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Class1.cs b/tests/ClientConfigTest.cs
similarity index 65%
copy from rocketmq-client-csharp/Class1.cs
copy to tests/ClientConfigTest.cs
index f98588c..c6d83cf 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/tests/ClientConfigTest.cs
@@ -1,24 +1,31 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+
+namespace org.apache.rocketmq {
+    [TestClass]
+    public class ClientConfigTest {
+        [TestMethod]
+        public void testClientId() {
+            var clientConfig = new ClientConfig();
+            string clientId = clientConfig.clientId();
+            Assert.IsTrue(clientId.Contains("@"));
+            Assert.IsTrue(clientId.Contains("#default"));
+        }
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Class1.cs b/tests/DateTimeTest.cs
similarity index 63%
copy from rocketmq-client-csharp/Class1.cs
copy to tests/DateTimeTest.cs
index f98588c..568d59e 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/tests/DateTimeTest.cs
@@ -1,24 +1,34 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+
+namespace org.apache.rocketmq {
+    
+    [TestClass]
+    public class DateTimeTest {
+        
+        [TestMethod]
+        public void testFormat() {
+            DateTime instant = new DateTime(2022, 02, 15, 08, 31, 56);
+            string time =  instant.ToString(MetadataConstants.DATE_TIME_FORMAT);
+            string expected = "20220215T083156Z";
+            Assert.AreEqual(time, expected);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Class1.cs b/tests/SendResultTest.cs
similarity index 50%
copy from rocketmq-client-csharp/Class1.cs
copy to tests/SendResultTest.cs
index f98588c..8dd033a 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/tests/SendResultTest.cs
@@ -1,24 +1,44 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace org.apache.rocketmq {
+
+    [TestClass]
+    public class SendResultTest {
+
+        [TestMethod]
+        public void testCtor() {
+            string messageId = new string("abc");
+            var sendResult = new SendResult(messageId);
+            Assert.AreEqual(messageId, sendResult.MessageId);
+            Assert.AreEqual(SendStatus.SEND_OK, sendResult.Status);
+        }
+
+
+        [TestMethod]
+        public void testCtor2() {
+            string messageId = new string("abc");
+            var sendResult = new SendResult(messageId, SendStatus.FLUSH_DISK_TIMEOUT);
+            Assert.AreEqual(messageId, sendResult.MessageId);
+            Assert.AreEqual(SendStatus.FLUSH_DISK_TIMEOUT, sendResult.Status);
+        }
+
+    }
+    
+}
\ No newline at end of file
diff --git a/tests/SignatureTest.cs b/tests/SignatureTest.cs
new file mode 100644
index 0000000..cece257
--- /dev/null
+++ b/tests/SignatureTest.cs
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using grpc = global::Grpc.Core;
+using Moq;
+using System;
+
+namespace org.apache.rocketmq {
+
+    [TestClass]
+    public class SignatureTest {
+
+        [TestMethod]
+        public void testSign()
+        {
+            var mock = new Mock<IClientConfig>();
+            mock.Setup(x => x.getGroupName()).Returns("G1");
+            mock.Setup(x => x.tenantId()).Returns("Tenant-id");
+            mock.Setup(x => x.resourceNamespace()).Returns("mq:arn:test:");
+            mock.Setup(x => x.serviceName()).Returns("mq");
+            mock.Setup(x => x.region()).Returns("cn-hangzhou");
+            
+            string accessKey = "key";
+            string accessSecret = "secret";
+            var credentialsProvider = new StaticCredentialsProvider(accessKey, accessSecret);
+            mock.Setup(x => x.credentialsProvider()).Returns(credentialsProvider);
+
+            var metadata = new grpc::Metadata();
+            Signature.sign(mock.Object, metadata);
+            Assert.IsNotNull(metadata.Get(MetadataConstants.AUTHORIZATION));
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/rocketmq-client-csharp/Class1.cs b/tests/StaticCredentialsProviderTest.cs
similarity index 52%
rename from rocketmq-client-csharp/Class1.cs
rename to tests/StaticCredentialsProviderTest.cs
index f98588c..20b957e 100644
--- a/rocketmq-client-csharp/Class1.cs
+++ b/tests/StaticCredentialsProviderTest.cs
@@ -1,24 +1,37 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-using System;
-
-namespace rocketmq_client_csharp
-{
-    public class Class1
-    {
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+
+namespace org.apache.rocketmq {
+    [TestClass]
+    public class StaticCredentialsProviderTest {
+
+        [TestMethod]
+        public void testGetCredentials() {
+            var accessKey = "key";
+            var accessSecret = "secret";
+            var provider = new StaticCredentialsProvider(accessKey, accessSecret);
+            var credentials = provider.getCredentials();
+            Assert.IsNotNull(credentials);
+            Assert.IsFalse(credentials.expired(), "Credentials from StaticCredentialsProvider should never expire");
+            Assert.AreEqual(credentials.AccessKey, accessKey);
+            Assert.AreEqual(credentials.AccessSecret, accessSecret);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/tests/TopicTest.cs b/tests/TopicTest.cs
new file mode 100644
index 0000000..fcc15e4
--- /dev/null
+++ b/tests/TopicTest.cs
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Collections.Generic;
+
+namespace org.apache.rocketmq {
+     
+     [TestClass]
+     public class TopicTest {
+
+         [TestMethod]
+         public void testCompareTo() {
+            List<Topic> topics = new List<Topic>();
+            topics.Add(new Topic("ns1", "t1"));
+            topics.Add(new Topic("ns0", "t1"));
+            topics.Add(new Topic("ns0", "t0"));
+
+            topics.Sort();
+
+            Assert.AreEqual(topics[0].ResourceNamespace, "ns0");
+            Assert.AreEqual(topics[0].Name, "t0");
+
+            Assert.AreEqual(topics[1].ResourceNamespace, "ns0");
+            Assert.AreEqual(topics[1].Name, "t1");
+            
+
+            Assert.AreEqual(topics[2].ResourceNamespace, "ns1");
+            Assert.AreEqual(topics[2].Name, "t1");
+            
+        }
+
+
+     }
+ }
\ No newline at end of file
diff --git a/tests/UnitTest1.cs b/tests/UnitTest1.cs
index bdc4aa3..4689e52 100644
--- a/tests/UnitTest1.cs
+++ b/tests/UnitTest1.cs
@@ -1,5 +1,8 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
-
+using org.apache.rocketmq;
+using Grpc.Net.Client;
+using apache.rocketmq.v1;
+using System;
 namespace tests
 {
     [TestClass]
@@ -8,6 +11,40 @@ namespace tests
         [TestMethod]
         public void TestMethod1()
         {
+            apache.rocketmq.v1.Permission perm = apache.rocketmq.v1.Permission.None;
+            switch(perm) {
+                case apache.rocketmq.v1.Permission.None:
+                {
+                    Console.WriteLine("None");
+                    break;
+                }
+
+                case apache.rocketmq.v1.Permission.Read:
+                {
+                    Console.WriteLine("Read");
+                    break;
+                }
+
+                case apache.rocketmq.v1.Permission.Write:
+                {
+                    Console.WriteLine("Write");
+                    break;
+                }
+
+                case apache.rocketmq.v1.Permission.ReadWrite:
+                {
+                    Console.WriteLine("ReadWrite");
+                    break;
+                }
+
+            }
+        }
+
+        [TestMethod]
+        public void TestRpcClientImplCtor() {
+            using var channel = GrpcChannel.ForAddress("https://localhost:5001");
+            var client = new MessagingService.MessagingServiceClient(channel);
+            RpcClient impl = new RpcClient(client);
         }
     }
 }
diff --git a/tests/tests.csproj b/tests/tests.csproj
index a70533f..578fe4e 100644
--- a/tests/tests.csproj
+++ b/tests/tests.csproj
@@ -8,6 +8,7 @@
 
   <ItemGroup>
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
+    <PackageReference Include="Moq" Version="4.16.1" />
     <PackageReference Include="MSTest.TestAdapter" Version="2.2.3" />
     <PackageReference Include="MSTest.TestFramework" Version="2.2.3" />
     <PackageReference Include="coverlet.collector" Version="3.0.2" />