Self-hosted service
microsurging/surging avatar
microsurging/surging

Surging: a C# RPC and microservice engine built around ServiceHostBuilder

Surging is a micro-service engine that provides a lightweight, high-performance, modular RPC request pipeline. support Event-based Asynchronous Pattern and reactive programming.

3,264 stars916 forksC#MIT

At a glance

What is it?
Surging is a .NET microservice engine from the microsurging/surging repository that wires RPC transport, service discovery, load balancing and fault tolerance into one host builder. This review covers what the README documents, where it stays silent, and who should think twice.
Who is it for?
Adopt Surging if your team already runs .NET, wants a ServiceHostBuilder that bundles transport, serialization, discovery and fault tolerance, and is willing to read the source because the README is a code dump rather than a manual. Do not adopt it if you need documented upgrade paths, a stable API surface, or a pipeline you can debug without prior knowledge of the project.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 174 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Surging is for, and the problem it removes

Surging targets .NET teams building service-oriented systems where each business module is deployed and scaled on its own. The README defines a microservice as something that can be freely split and recombined, where each service is highly autonomous across development and deployment, does one thing, and uses domain-driven design to reach a finer grain. That is the stated intent, not a claim about how projects actually end up.

The concrete problem it removes is the wiring. Without a framework of this kind, a service host has to register itself with a discovery backend, expose an RPC endpoint, pick a serializer, apply a load balancing rule, decide what happens when a downstream call fails, and pull configuration from somewhere that can change at runtime. Surging folds all of that into one builder. The README lists the capabilities it wants credit for: simplified service invocation through service rules, automatic registration and discovery via ServiceId or RoutePath, internal load balancing and fault tolerance, a distributed cache middleware using consistent hashing with health checks, an event bus for publish and subscribe, containerized CI/CD, and a modular business engine that loads specified modules so different versions can be deployed independently.

It is aimed at engineers who are comfortable in C# and already accept that a microservice deployment means Zookeeper or Consul, a message broker, and a cache tier. It is not a framework for people who want to add a package and get a working HTTP API in ten minutes.

Inside the ServiceHostBuilder pipeline

The mechanism is visible in the configuration sample the README provides. A ServiceHostBuilder is constructed, then RegisterServices takes a builder lambda where AddMicroService configures the runtime. Inside that block, the developer turns on service runtime, relate service (which the comment says adds support for proxy remote invocation), and configuration watch, which adds a listener for synchronized config file updates. Then a discovery backend is chosen: UseZooKeeperManager with a ConfigInfo such as 127.0.0.1:2181, or UseConsulManager with 127.0.0.1:8500. Transport comes next, either UseDotNettyTransport or UseRabbitMQTransport, and the README notes that RPC can use netty or thrift with asynchronous non-blocking transfer. Serialization is a separate switch: UseProtoBufferCodec or UseMessagePackCodec.

The host-level options carry the runtime policy. UseServer accepts either a positional form (IP, port, and optionally a token flag or a fixed password) or an options object with Ip, Port, ExecutionTimeoutInMilliseconds, Strategy, RequestCacheEnabled, Injection, InjectionNamespaces, BreakeErrorThresholdPercentage, BreakeSleepWindowInMilliseconds, BreakerForceClosed, BreakerRequestVolumeThreshold, MaxConcurrentRequests, ShuntStrategy and NotRelatedAssemblyFiles. Those names describe a circuit breaker with a request volume threshold, a sleep window and a force-close switch, plus a shunt strategy for address selection. The README shows AddressSelectorMode.Polling for round-robin and mentions hashing, random, polling and least-pressure as the load balancing algorithms.

Two details are worth flagging. First, the README states that request caching only takes effect when the call goes through interface proxy remote invocation, so enabling RequestCacheEnabled on a local call does nothing. Second, the circuit breaker option is spelled BreakeErrorThresholdPercentage, with the typo baked into the API. That is the kind of thing you discover by reading the code, not the docs.

Installing Surging and starting a first host

The README gives two distribution channels. For containers, the Docker Hub image is serviceengine/surging, pulled with a version tag. For .NET projects, the package is installed through NuGet with Install-Package surging -Version followed by the version number. The README does not state which version numbers are available, so the tag and the version string have to come from the registry or the release notes rather than from the documentation.

A minimal host follows the shape in the README. The block below is the smallest configuration the documentation shows, with the Consul manager, Netty transport and MessagePack codec selected:

csharp
var host = new ServiceHostBuilder()
    .RegisterServices(builder =>
    {
        builder.AddMicroService(option =>
        {
            option.AddServiceRuntime();
            option.AddRelateService();
            option.AddConfigurationWatch();
            option.UseConsulManager(new ConfigInfo("127.0.0.1:8500"));
            option.UseDotNettyTransport();
            option.UseMessagePackCodec();
            builder.Register(p => new CPlatformContainer(ServiceLocator.Current));
        });
    })
    .SubscribeAt()
    .UseServer(options => {
        options.Ip = "127.0.0.1";
        options.Port = 98;
        options.ExecutionTimeoutInMilliseconds = 30000;
        options.Strategy = (int)StrategyType.Failover;
    })
    .UseProxy()
    .UseStartup<Startup>()
    .Build();

using (host.Run())
{
    Console.WriteLine($"服务端启动成功,{DateTime.Now}。");
}

When the host runs, the README's example prints a startup line to the console. A Consul agent has to be listening on 127.0.0.1:8500 before that happens, because the registration call goes out during startup.

Configuration values are read from JSON files with environment variable overrides in the form ${Name}|default. The register connection entry below falls back to 127.0.0.1:8500 when Register_Conn is unset:

json
{
  "ConnectionString": "${Register_Conn}|127.0.0.1:8500",
  "SessionTimeout": "${Register_SessionTimeout}|50",
  "ReloadOnChange": true
}

For a container deployment the README shows a separate shape with Ip defaulting to 0.0.0.0, Port defaulting to 98, and MappingIp and MappingPort for the public host address. Routes are declared with the ServiceBundle attribute, for example [ServiceBundle("api/{Service}")], and an endpoint can require JWT or AppSecret by adding [Authorization(AuthType = AuthorizationType.JWT)] or [Authorization(AuthType = AuthorizationType.AppSecret)] to the method. Event subscriptions are started explicitly with ServiceLocator.GetService<ISubscriptionAdapt>().SubscribeAt().

Fault tolerance, injection and cache fallback

Surging's fault tolerance is expressed through the Command attribute. The README shows a Strategy of StrategyType.Injection combined with an Injection string, and the simplest form returns null:

csharp
[Command(Strategy= StrategyType.Injection ,Injection = @"return null;")]

The same mechanism can return a constructed object, provided the types used are listed in InjectionNamespaces. The README's example returns a UserModel with Name set to fanly and Age set to 18, and passes InjectionNamespaces = new string[] { "Surging.IModuleServices.Common" }. The script is compiled against those namespaces, so anything not listed is not visible to it. That is a hard boundary worth understanding before you rely on injection for production fallbacks.

Cache fallback is a separate attribute setting. The README shows [Command(Strategy= StrategyType.Failover,FailoverCluster =3,RequestCacheEnabled =true)] and states that RequestCacheEnabled must be true for the cache path to apply. The FailoverCluster value of 3 in that example is not explained anywhere in the README, so what it counts, retries or nodes, has to be read from the source.

One design consequence stands out. Because injection is a string of C# compiled at runtime, a typo in the injection script is not a compile error. It surfaces when the fallback path is exercised, which is precisely when you least want a surprise. Teams that adopt this should treat injection strings as code under test.

Where Surging is the wrong tool

The documentation is the first limitation. The README is a Chinese-language page whose English counterpart is referenced as README.EN.md, and the bulk of the body is an annotated code sample rather than prose. There is no documented rollback procedure, no compatibility matrix for the discovery backends, no statement about which .NET runtime versions are supported, and no explanation of FailoverCluster. The repository does carry a RELEASE_NOTES.md, but the README does not reference it.

The release history is the second signal. The listed releases are 1.0.0 on 2018-12-31, 0.6.7 for Surging.ApiGateway on 2018-06-02, and 0.5.1 for the same gateway on 2018-01-07. The last push to the repository was on 2026-04-10, so work has continued, but the published release tags stop in 2018. Anyone pinning a version from the release list is pinning something from that era, and the README gives no guidance on what changed afterwards.

The third limitation is operational. Surging assumes a discovery backend, and the README's examples assume Consul on 127.0.0.1:8500 or Zookeeper on 127.0.0.1:2181. If your team runs Kubernetes with its own service abstraction, you are adding a second registry that has to be kept in step. Similarly, the event bus configuration is loaded from eventBusSettings.json and the cache from cacheSettings.json with optional: false, so both files must exist or the host fails to build. For a small team with three services and no broker, this is infrastructure you would be maintaining for no benefit.

How Surging differs from gRPC plus a service mesh

The closest alternative for a .NET team is gRPC on top of ASP.NET Core, with service discovery and traffic policy pushed into a mesh such as Istio or Linkerd. The approaches differ in where the policy lives. Surging puts load balancing, circuit breaking, caching and fault injection inside the application host, configured through the ServiceHostBuilder options and the Command attribute on individual methods. A mesh puts those concerns in a sidecar proxy, outside the process, and the application speaks plain gRPC.

The trade-off is visibility and coupling. With Surging, a method-level fallback such as returning a cached value or a default object is a one-line attribute, and the framework knows the method's return type well enough to compile a script against it. A sidecar cannot do that, because it does not understand your method signatures. On the other side, Surging's policy is compiled into the service, so changing a circuit breaker threshold means redeploying, and the framework's own configuration surface becomes part of your application's upgrade burden. A mesh lets you change traffic policy without touching the service binary.

The README also positions Surging against raw Netty or Thrift usage by pointing out that RPC transport can be either, with asynchronous non-blocking transfer. That is a lower-level comparison. The more useful framing is this: Surging is a framework that owns your request pipeline, and a mesh is a layer that does not.

Maintenance cost, licensing and what to check before adopting

Surging is licensed under MIT, per the badge in the README and the LICENSE file at the repository root. MIT permits use, modification and redistribution with the licence and copyright notice retained. That is the extent of what the repository states; questions about patent grants, contributor agreements or trademark use are not addressed by the material and would need their own review.

Upgrade cost is harder to estimate from the README alone. The release list ends in 2018 while the last push was on 2026-04-10, so there is a long stretch of commits with no published release notes visible in the release list. The repository does contain RELEASE_NOTES.md, and reading it is the only way to know what changed. The API surface also carries names that look like they were set early and never revisited, including BreakeErrorThresholdPercentage and BreakeSleepWindowInMilliseconds. Renaming those would break every existing configuration, so they are likely permanent.

Before adopting, check three things. Confirm the exact NuGet version you intend to install actually resolves, since the README does not list versions. Confirm which discovery backend your target environment already provides, because the choice between UseZooKeeperManager and UseConsulManager is made at host build time. And confirm that eventBusSettings.json and cacheSettings.json exist in your deployment, because both are loaded with optional: false and the host will not build without them.

Editorial conclusion

Adopt Surging if your team already runs .NET, wants a ServiceHostBuilder that bundles transport, serialization, discovery and fault tolerance, and is willing to read the source because the README is a code dump rather than a manual. Do not adopt it if you need documented upgrade paths, a stable API surface, or a pipeline you can debug without prior knowledge of the project. Verify first that the NuGet package version you intend to install actually exists, and read RELEASE_NOTES.md before pinning anything.

Frequently asked questions

How do I install Surging?

The README gives two routes: pull the Docker Hub image serviceengine/surging with a version tag, or install the NuGet package with Install-Package surging -Version followed by a version number. The README does not list which versions exist, so the version string has to come from the registry or the release notes.

What discovery backends does Surging support?

The README shows UseZooKeeperManager with a ConfigInfo such as 127.0.0.1:2181 and UseConsulManager with 127.0.0.1:8500, selected inside AddMicroService. The repository topics also list consul and zookeeper.

Which serialization formats can Surging use for RPC?

The README shows two codec switches, UseProtoBufferCodec for protobuf and UseMessagePackCodec for MessagePack, chosen alongside the transport. Transport itself is selected separately with UseDotNettyTransport or UseRabbitMQTransport.

Does Surging support JWT authentication on service methods?

Yes. The README states that adding [Authorization(AuthType = AuthorizationType.JWT)] to an interface method enables JWT validation, and [Authorization(AuthType = AuthorizationType.AppSecret)] enables AppSecret validation.

What is the latest release of Surging?

The release list shows 1.0.0 dated 2018-12-31, with 0.6.7 and 0.5.1 before it as Surging.ApiGateway releases. The repository's last push was on 2026-04-10, so commits have continued past the last tagged release, and RELEASE_NOTES.md is the place to look for what changed.

Official sources

  1. License: MIT
  2. microsurging/surging on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/microsurging-surging.svg)](https://hysenlabs.com/projects/microsurging-surging)