---
id: generateproxyfromserver
title: 从服务端生成代理
---

## 一、生成代理

在开发过程中，如果服务器和客户端，都是我们自己开发的话（在同一个电脑），就可以使用本地代理生成。

调用下列代码，会将已注册的所有服务，导出代理为字符串。

RpcStore是**实例**，或者是IRpcParser的**属性**。

```csharp
string code=RpcStore.GetProxyCodes("MyNameSpace"));
```

【示例1】
将代理字符串，写成.cs文件，然后通过链接的形式，将代码添加到客户端项目。

服务器代码，在服务器执行后，会在运行路径下，生成一个**WhisperServers.cs**的文件。

```csharp {14}
var service = new TcpTouchRpcService();
var config = new TouchSocketConfig()//配置
                   .SetListenIPHosts(new IPHost[] { new IPHost(port) })
                   .ConfigureContainer(a =>
                   {
                       a.AddConsoleLogger();
                       a.AddFileLogger();
                   })
                   .ConfigureRpcStore(a =>
                   {
                       a.RegisterServer<MyRpcServer>();//注册服务

#if DEBUG
                       File.WriteAllText("../../../WhisperServers.cs", a.GetProxyCodes("WhisperServers",new Type[] { typeof(TouchRpcAttribute) }));
#endif
                   })
                   .SetVerifyToken("TouchRpc");

            service.Setup(config)
                .Start();
```

然后打开需要引入的**客户端**解决方案。选择需要添加代理的项目，依次执行：

**右击项目=>添加=>现有项**

**然后选择服务器生成的.cs文件，选择“添加”的下拉框，选择“添加为连接”。**

<img src={require('@site/static/img/docs/generateproxy-2.png').default} />
<img src={require('@site/static/img/docs/generateproxy-3.png').default} />


最后确认文件被正确添加为链接。
<img src={require('@site/static/img/docs/generateproxy-4.png').default} />

**这样，每次当服务有更新的时候，只需要启动一下服务器，代理就会自动刷新。**

:::caution 注意

上述操作仅对**客户端**与**服务器**都在同一电脑上开发时才有效。

:::  

:::tip 提示

当不在同一个电脑上时，可将代理信息写成文件，直接发给客户端开发电脑。亦或者，为防止篡改生成的代码，不想把代理代码直接投入使用，那可以考虑将代码单独编译成dll，然后将编译的程序集发送。

:::  

:::tip 提示

上述行为，均是导出所有已注册的服务，当需要直接生成多个不同代理的源码时，可通过CodeGenerator静态类的相关方法直接生成。例如：

```csharp {1}
string codes=CodeGenerator.GetProxyCodes("Namespace",new Type[]{typeof(RpcServer) },new Type[] { typeof(TouchRpcAttribute)});
```

:::  


## 二、代理类型添加

通过之前的学习，大家可能大概明白了，在Rpc中，客户端与服务器在进行交互时，所需的数据结构不要求是同一类型，。所以在声明了服务以后，服务中所包含的自定义类型，会被复刻成结构相同的类型，但是这也仅仅局限于参数与服务`相同程序集`的时候。如果服务中引入了其他程序集的数据结构，则**不会**复刻。

但是，往往在服务端开发中，会引入其他程序集，例如，我们习惯在项目中建立一个Models程序集，用于存放所有的实体模型，那是不是意味着客户端也必须引入这个程序集才能调用呢？没别的方法了？

**答案，当然不是！！！**

Rpc规范了两种方式来添加实体模型的复刻。

### 2.1 直接添加代理类型

在服务注册之前，任意时刻，可调用CodeGenerator.AddProxyType静态方法，添加代理类型，同时可传入一个bool值，表明是否深度搜索，比如，假如ProxyClass1中还有其他类型，则参数为True时，依然会代理。

```csharp
CodeGenerator.AddProxyType<ProxyClass1>();
CodeGenerator.AddProxyType<ProxyClass2>(deepSearch:true);
```

或者直接按程序集添加

```csharp
CodeGenerator.AddProxyAssembly(typeof(Program).Assembly);
```

### 2.2 通过特性标记添加

在需要代理的类上面声明RpcProxy标签，然后也可以重新指定代理类名。

```csharp
[RpcProxy("MyArgs")]
public class Args
{
}
```

:::tip 提示

该场景可用于代理其他dll的自定义类型。

:::  

## 三、代理类型排除

默认情况下，与声明服务相同的自定义类型，会被代理复刻成结构相同的类型。但是有时候，我们希望服务端与客户端公用一个dll，所以就不需要复刻，那么可以排除代理类型。

```csharp
CodeGenerator.AddIgnoreProxyType(typeof(Program));
```

或者直接按程序集排除

```csharp
CodeGenerator.AddIgnoreProxyAssembly(typeof(Program).Assembly);
```

:::tip 提示

该场景可用于服务端与客户端公用一个实体dll，例如：当使用**MemoryPack**序列化的场景。

:::  