简体   繁体   English

根据 C# 中的用户输入调用不同 API 的最佳方式?

[英]Best way to call different APIs based on user input in C#?

I am developing one console application using C#.我正在使用 C# 开发一个控制台应用程序。 I need to call different-2 get APIs based on the input provided by the user and write the response on console.我需要根据用户提供的输入调用 different-2 get API 并将响应写入控制台。

So if user enters 1, I need to call a group weather api.所以如果用户输入1,我需要调用一个组天气api。 If user enters 2 then I need to call temperature API.如果用户输入 2 那么我需要调用温度 API。 If user enters 3 then call some other API and if enters other then this just write invalid input.如果用户输入 3 则调用其他 API,如果输入其他 API,则仅写入无效输入。

For now I have just written multiple if and else if .现在我刚刚写了多个ifelse if Is there any better approach?有没有更好的方法? Because this way there are multiple if else.因为这种方式有多个if else。 And same goes for switch case as well.开关盒也是如此。

I have also thought of creating mapping of input the endpoint like defining them in config file and then read into a dictionary.我还考虑过创建输入端点的映射,例如在配置文件中定义它们,然后读入字典。

So in future it can support below things.因此,将来它可以支持以下内容。

if I need to call another API for input 4….. or No need to call any API for input 2. Or call different API on input 2.如果我需要为输入 4 调用另一个 API……或者不需要为输入 2 调用任何 API。或者在输入 2 上调用不同的 API。

well one way around this is to use Dictionary and Action :解决这个问题的一种方法是使用DictionaryAction

private static readonly Dictionary<string, Action> MyApiCalls= new()
    {
        {
            "1", () =>
            {
                Console.WriteLine("im cool");
            }
        },

        {
            "2", () =>
            {
                Console.WriteLine("im really cool");
            }
        }
    };

and you use it like this :你像这样使用它:

 static void Main(string[] args)
    {
        var input = Console.ReadLine() ?? "1";

        MyApiCalls[input]();

        Console.ReadKey();
    }

so the action can be your api call or anything else.因此该操作可以是您的 api 调用或其他任何操作。

if the number of cases is limited, I suggest to stick to a switch (cleaner then if-else in my opinion).如果案例数量有限,我建议坚持使用开关(我认为比 if-else 更干净)。 A switch doesn't cost anything in speed.开关不会花费任何速度。

Happy programming!快乐编程!

You can use Strategy pattern .您可以使用策略模式 In addition, it is necessary to use Factory method pattern to resolve API instances.此外,需要使用工厂方法模式来解析 API 实例。

You can choose any strategy at the runtime based on your parameter.您可以在运行时根据您的参数选择任何策略。

Let me show an example of implementation.让我展示一个实现的例子。 So we need some user types:所以我们需要一些用户类型:

public enum UserInput
{
    One, Two, Three
}

And some abstractions that can be implemented by API strategies:以及一些可以通过 API 策略实现的抽象:

public abstract class BaseApi
{
    public abstract string Get();
}

And its concrete implementations:及其具体实现:

public class WeatherApi : BaseApi
{
    public override string Get() => "I am weather API";
}

public class TemperatureApi : BaseApi
{
    public override string Get() => "I am temperature Api";
}

And it is necessary to implement Factory pattern to generate API strategies by UserInput :并且需要实现工厂模式来通过UserInput生成 API 策略:

public class ApiFactory
{
    private Dictionary<UserInput, BaseApi> _apiByUserInput { get; set; }
        = new Dictionary<UserInput, BaseApi>
        {
            { UserInput.One, new WeatherApi() },
            { UserInput.Two, new TemperatureApi() }
        };

    public BaseApi GetInstance(UserInput userInput) => _apiByUserInput[userInput];
}

And this is a method which works with ApiFactory:这是一种适用于 ApiFactory 的方法:

string CallApiByUserInput(UserInput userInput) 
{
    ApiFactory apiFactory = new ApiFactory();
    BaseApi weatherApi = apiFactory.GetInstance(userInput);
    return weatherApi.Get();
}

And then code can be called like this:然后可以这样调用代码:

Console.WriteLine(CallApiByUserInput(UserInput.One)); // OUTPUT: "I am weather API"

UPDATE更新

If you want to have a single instance of your API's, then let me show some ways.如果您想拥有 API 的单个实例,那么让我展示一些方法。

The first way第一种方式

If you are using IoC container, then you can set object lifescope.如果您使用的是 IoC 容器,那么您可以设置对象生命周期。

Let me show an example for ASP.NET Core.让我展示一个 ASP.NET Core 的示例。

Register all in the DI in your Startup.cs:在 Startup.cs 的 DI 中注册所有内容:

public void ConfigureServices(IServiceCollection services)
{
    // ... other code is omitted for the brevity
    services.AddSingleton<WeatherApi>();
    services.AddScoped<TemperatureApi>(); // this can be Singleton 
        // or Transient as well, depending on your needs
    // ... other code is omitted for the brevity
}

and inject your dependencies through constructor of ApiFactory :并通过ApiFactory的构造函数注入您的依赖项:

public class ApiFactory
{
    private Dictionary<UserInput, BaseApi> _apiByUserInput;

    public ApiFactory(WeatherApi weatherApi, TemperatureApi temperatureApi)
    {
        _apiByUserInput = new Dictionary<UserInput, BaseApi>()
        {
            { UserInput.One, weatherApi },
            { UserInput.Two, temperatureApi }
        };
    }

    public BaseApi GetInstance(UserInput userInput) => _apiByUserInput[userInput];
}

The second way第二种方式

Make ApiFactory to be static :使ApiFactory成为static的:

public class ApiFactory
{
    private static Dictionary<UserInput, BaseApi> _apiByUserInput { get; set; }
        = new Dictionary<UserInput, BaseApi>
        {
            { UserInput.One, new WeatherApi() },
            { UserInput.Two, new TemperatureApi() }
        };

    public BaseApi GetInstance(UserInput userInput) => _apiByUserInput[userInput];
}

and it can be called like this:它可以这样调用:

Console.WriteLine(CallApiByUserInput(UserInput.One)); // I am weather API 2022-07-21 11:01
Thread.Sleep(3000);
Console.WriteLine(CallApiByUserInput(UserInput.Two)); // I am temperature API 2022-07-21 11:01

I'm sceptical of我对此表示怀疑

I have also thought of creating mapping of input the endpoint like defining them in config file and then read into a dictionary.我还考虑过创建输入端点的映射,例如在配置文件中定义它们,然后读入字典。

because different API will have different return object and you need custom code to extract the relevant data.因为不同的 API 会有不同的返回对象,你需要自定义代码来提取相关数据。

I think switch has a good balance of simplicity and flexibility:我认为switch在简单性和灵活性之间取得了很好的平衡:

await answer switch 
{
        "1" => CallWeatherApiAsync(),
        "2" => CallTemperatureApiAsync(),
        _ => throw / continue (if in a loop)
}

You could also use a collection Action / Func<Task> :您还可以使用集合Action / Func<Task>

Dictionary<string, (string Description, Func<Task> Work)> functionality; 
List<(string Key, string Description, Func<Task> Work)> functionality;

Please remember that you may need to balance generality and specific behaviours.请记住,您可能需要平衡一般性和特定行为。 For example, you may require extra input for certain functions.例如,您可能需要对某些功能进行额外输入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM