# Viper: a dashboard and sample suite built on the Anno microservice engine

> Viper is a dashboard and sample project for the Anno distributed development framework, showing service discovery, tracing, rate limiting and an event bus over gRPC or Thrift. It suits .NET teams evaluating Anno by running the reference implementation end to end, and it is a sample application rather than a framework in its own right.

**duyanming/Viper** — Viper 是一个基于Anno微服务引擎开发的Dashboard示例项目。Anno 底层通讯采用 grpc、thrift。自带服务发现、调用链追踪、Cron 调度、限流、事件总线等等

- Repository: https://github.com/duyanming/Viper
- Website: http://anno.liqingxi.cn/
- Stars: 754 · Forks: 180
- Language: C#
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/duyanming-viper

## A dashboard and sample suite, not the framework itself

Viper is described as a Dashboard project and sample project built on the Anno microservice engine, with the Anno engine itself living in a separate repository, Anno.Core. That distinction is the first thing to understand, because it decides what you are looking at.

Anno is a distributed development framework supporting .NET Core 3.1, .NET Framework 4.5 and Java, and its underlying transport can be gRPC or Thrift. The feature list the project carries is the engine's: service discovery, call chain tracing, Cron scheduling, rate limiting and an event bus, all built in.

Viper is where you see those capabilities exercised. The README walks through starting a service registry, starting a service that registers itself, starting an API gateway, then looking at the dashboard for call chain details, cluster routing information, service performance monitoring and the result of a test email call. Each of those steps has a screenshot in the README, so the page doubles as a tour of what the dashboard shows.

The audience is a .NET developer evaluating the Anno stack, or a team that wants a working reference to copy from. A separate Java implementation is linked as well, in the anno.thrift-parent repository, which tells you the engine is meant to be used from more than one language.

## Three processes, started in a fixed order

Running Viper takes three processes, and the README is specific about the order because each one depends on the one before it.

The first is the registry, ViperCenter, configured through its own Anno.config file, and started with dotnet ViperCenter.dll from the built output directory. The second is ViperService, started with dotnet ViperService.dll, which registers itself with the registry on start. The third is the gateway, Viper.GetWay, whose behaviour is configured in Viper\Viper\appsettings.json.

The README points out that ViperService does not have to run on the same machine as ViperCenter, that you can run several servers, and that they can be load balanced. Advanced usage is said to come later in the documentation.

The configuration files are plain XML in the build output, and they are edited after a build rather than through a deployment pipeline. Each process has a bat file at the repository root, viperCenter.bat, viperService.bat and viperGateWayDebug.bat, which tells you these are meant to be launched locally as a set.

A live demo is published at anno.liqingxi.cn with the account anno and the password 123456, which is a quick way to see the dashboard before running anything yourself.

## Database bootstrap and the connection string

The persistence step comes first. The README instructs you to run the database script that creates the database, pointing at the file Viper\database\viper20210617_01.sql, and then to change the connection string in the viperService configuration file at Viper\ViperService\bin\Debug\net6.0\Anno.config.

The connection string entry itself is a single appSettings key:

```xml
    <add key="ConnStr" value="server=127.0.0.1;database=viper;uid=bif;pwd=123456;SslMode=None;"/>
```

So Viper expects MySQL, with the database named viper, and it ships a SQL script dated 2021-06-17 to create the schema.

The same configuration file also carries a commented out Redis section, with keys for the Redis connection string, the key prefix, the key expiry in minutes and a switch that turns the Redis usage off, the default in the sample being off. The README does not explain the schema behind those keys, so treat them as a starting point rather than a documented contract.

The net6.0 in the path is a reminder of the era of the sample. The build output the instructions point at is a net6.0 directory, while the framework description mentions .NET Core 3.1 and .NET Framework 4.5, so the sample was assembled across several target frameworks.

## Registration is a coordinate pair and a Servers entry

The registry configuration in ViperCenter\Anno.config shows how the pieces find each other. The registry listens on a Port of 7010 with a TimeOut of 120000, and it holds a Servers list of service nodes. The sample entry registers a node named for three plug assemblies, Anno.Plugs.LogicService, Anno.Plugs.TraceService and Anno.Plugs.ViperService, with nickname ViperService-01, an ip, a port of 7011, a timeout of 20000 and a weight of 1. The comment in the file notes that this content is written automatically after ViperService starts.

So registration is service discovery in the traditional sense: the service pushes its own address into the registry, and the registry assigns the nickname and the identity used for routing.

The service side carries the identity rules. IdWorker is a pair of numbers described as workstation first and data centre second, with the file noting that the two digit pair cannot be repeated across services but that the reversed pair is allowed. AppName is the name used in the registry entry, Port is the listening port, and Weight feeds the routing decision. There is also an IgnoreFuncName entry, with the file listing Trace and Logic as examples, and a Ts element pointing at the registry with Ip 127.0.0.1 and Port 7010.

Those two lines are the ones the README says you usually need to change:

```xml
  <Ts Ip="127.0.0.1" Port="7010"/>
```

## Rate limits live in the gateway appsettings.json

The gateway is where the throttling policy is expressed, and the Viper\Viper\appsettings.json file is the clearest piece of configuration in the repository.

The Target section points at the registry with an AppName of ApiGateway, an IpAddress of 127.0.0.1, a Port of 7010 and a TraceOnOff flag that turns call chain tracing on. The Limit section then defines a TagLimits list, where each entry has a channel and a router pattern, a timeSpan, an rps value and a limitSize. The patterns in the sample are the wildcard characters for channel and router, which means the first rule applies broadly.

There are two more layers. DefaultIpLimit gives a per-IP limit of 200 rps with a limitSize of 200 over a timeSpan of 1, and the IpLimits array overrides that for specific address ranges, one entry for a single host and another for the range 192.168.0.10 to 192.168.10.20. Finally there are White and Black lists of addresses that are allowed or blocked outright.

That structure, tagged limits, then default IP limits, then per-range overrides, then allow and block lists, is the part of the sample that is worth reading closely, because it shows the intended order of precedence in the engine.

## EventBus with an in-memory transport and RabbitMQ

The event bus section of the README shows both transports side by side, and the API is the same in each case.

The server configuration collects the assemblies that contain event handlers, then configures the RabbitMQ transport with a RabbitConfiguration object holding HostName, VirtualHost, UserName, Password and Port, subscribes an error notice handler that logs failures, and calls SubscribeAll with the collected handlers. The in-memory EventBus is configured the same way, with its own error notice handler and the same SubscribeAll call. The difference in the sample is only the transport, not the publishing code.

```c#
    //EventBus Support  InMemory and Rabbitmq
```

Publishing side, a message type derives from EventData and carries its own properties, for example a Message string. The subscriber side is a class in an EventHandler namespace that uses Anno.EventBus and the namespace of the event types, and the README shows how handlers are declared in the assemblies collected earlier.

The pattern is conventional publish and subscribe with a pluggable broker, and the interesting part for an evaluator is the failure path: the error notice hook receives the exchange, the routing key, the exception and the body, so a failed consumption is logged with its context rather than swallowed.

## The repository is a solution with plug services, not a package

The layout tells you what this project is. At the root there is Viper.sln and Directory.Build.props, and beside them the plug services that make up the running system: Anno.Plugs.LogicService, Anno.Plugs.TraceService, Anno.Plugs.ViperService, plus Anno.Plugs.MonitorService for the performance monitoring view and Anno.Plugs.DLockService for distributed locking. Anno.CommandBus, Anno.Common, Anno.Infrastructure, Anno.Redis and Anno.ViperLog are the supporting libraries.

The application side is Viper, ViperCenter, ViperService and Viper.GetWay, with Samples holding example projects including HelloWorldDto, HelloWorldService, an Mvc sample and further Plugs examples. There is a Trace directory, a Viper.Test project and a database directory holding the SQL script.

Two files deserve attention. key.snk is a strong name key file, which is what a .NET assembly signing setup needs, and it sits in version control here. And the whole thing is a source solution you build and run, not a NuGet package you reference, which is the practical difference between studying Anno through Viper and depending on Anno through Anno.Core.

The tests are named Viper.Test and the project also carries a Trace directory, but the README does not describe a test strategy, so the sample is better read as a runnable reference than as a maintained regression suite.

## MIT licensed, sample code, and a last push in June

The repository is MIT licensed, with the terms in the LICENSE file, and the primary language is C#.

There are no GitHub releases, which fits a sample project whose value is in the source rather than in a published binary. The repository is not archived and the last push was on 2026-06-11, so the configuration examples and paths in the README, some of which reference net6.0 build output and a 2021 SQL script, describe a project that has not been refreshed in a while. Anyone following the instructions literally should expect to adjust paths and target frameworks for a current .NET SDK.

The homepage points to anno.liqingxi.cn, and the live demo there uses a published account, which is a reasonable way to evaluate the dashboard before committing to running the three processes yourself.

The upstream boundary is worth restating because it decides where the real obligations sit. Viper carries an MIT licence and depends on Anno.Core, which is a separate project with its own licence, and the Java implementation lives in a third repository. If you end up shipping Viper-derived code, the licence of the Anno engine you actually depend on is the one to check, and this review does not interpret either set of terms.

## Conclusion

Viper fits a .NET team that wants to see the Anno microservice engine working before committing to it, because it ships the registry, the service, the gateway, the database script and the configuration for all three in one solution. It does not fit a team looking for a production framework, since the framework itself lives in the separate Anno.Core repository and this project is explicitly described as a dashboard and sample. Before you base anything on it, run the three processes in the order the README gives, confirm the ViperCenter port and the ViperService registration entry match your machine, and read the licence of the Anno.Core project you actually depend on.

## FAQ

### How do I run the Viper dashboard locally?

Run the database script Viper\database\viper20210617_01.sql first, then start the registry with dotnet ViperCenter.dll, the service with dotnet ViperService.dll so it registers itself, and finally the Viper.GetWay gateway.

### What is the difference between Viper and Anno.Core?

Viper is the dashboard and sample project that demonstrates the Anno distributed development framework, while Anno.Core is the separate repository that holds the framework itself, with service discovery, tracing, Cron scheduling, rate limiting and an event bus.

### Where are the rate limits configured in Viper?

In Viper\Viper\appsettings.json, with a Target section for the gateway and a Limit section holding TagLimits, a DefaultIpLimit, per-range IpLimits entries and White and Black address lists.

### Does Viper support RabbitMQ as well as an in-memory event bus?

Yes. The README shows both transports configured in the same way, with RabbitMQEventBus using a RabbitConfiguration of host name, virtual host, credentials and port, and the in-memory EventBus configured in parallel, both subscribing all collected handlers.

## Sources

- [duyanming/Viper on GitHub](https://github.com/duyanming/Viper)
- [Issues](https://github.com/duyanming/Viper/issues)
- [License: MIT](https://github.com/duyanming/Viper/blob/master/LICENSE)
- [Project website](http://anno.liqingxi.cn/)
- [README](https://github.com/duyanming/Viper/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/duyanming-viper
