add voice service call service and more
This commit is contained in:
18
src/GreenHome.VoiceCall.Avanak/AvanakVoiceCallOptions.cs
Normal file
18
src/GreenHome.VoiceCall.Avanak/AvanakVoiceCallOptions.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace GreenHome.VoiceCall.Avanak;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration options for Avanak Voice Call service
|
||||
/// </summary>
|
||||
public sealed class AvanakVoiceCallOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Avanak API base URL
|
||||
/// </summary>
|
||||
public string BaseUrl { get; set; } = "https://portal.avanak.ir/Rest";
|
||||
|
||||
/// <summary>
|
||||
/// Avanak authorization token
|
||||
/// </summary>
|
||||
public required string Token { get; set; }
|
||||
}
|
||||
|
||||
220
src/GreenHome.VoiceCall.Avanak/AvanakVoiceCallService.cs
Normal file
220
src/GreenHome.VoiceCall.Avanak/AvanakVoiceCallService.cs
Normal file
@@ -0,0 +1,220 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace GreenHome.VoiceCall.Avanak;
|
||||
|
||||
/// <summary>
|
||||
/// Avanak Voice Call service implementation
|
||||
/// </summary>
|
||||
public sealed class AvanakVoiceCallService : IVoiceCallService
|
||||
{
|
||||
private readonly HttpClient httpClient;
|
||||
private readonly AvanakVoiceCallOptions options;
|
||||
private readonly ILogger<AvanakVoiceCallService> logger;
|
||||
|
||||
public AvanakVoiceCallService(
|
||||
HttpClient httpClient,
|
||||
AvanakVoiceCallOptions options,
|
||||
ILogger<AvanakVoiceCallService> logger)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
this.options = options;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<AccountStatusResponse?> GetAccountStatusAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await httpClient.PostAsync(
|
||||
"AccountStatus",
|
||||
null,
|
||||
cancellationToken);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<AccountStatusResponse>(
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
logger.LogError(ex, "Error getting account status");
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Unexpected error getting account status");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<GenerateTTSResponse?> GenerateTTSAsync(GenerateTTSRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await httpClient.PostAsJsonAsync(
|
||||
"GenerateTTS",
|
||||
request,
|
||||
cancellationToken);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<GenerateTTSResponse>(
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
logger.LogError(ex, "Error generating TTS for text: {Text}", request.Text);
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Unexpected error generating TTS");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<QuickSendResponse?> QuickSendAsync(QuickSendRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await httpClient.PostAsJsonAsync(
|
||||
"QuickSend",
|
||||
request,
|
||||
cancellationToken);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<QuickSendResponse>(
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
logger.LogError(ex, "Error sending quick voice call to {Recipient}", request.Recipient);
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Unexpected error sending quick voice call");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<QuickSendWithTTSResponse?> QuickSendWithTTSAsync(QuickSendWithTTSRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Build form data according to Avanak API documentation
|
||||
var formData = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new("Text", request.Text),
|
||||
new("Number", request.Number)
|
||||
};
|
||||
|
||||
if (request.Vote.HasValue)
|
||||
{
|
||||
formData.Add(new KeyValuePair<string, string>("Vote", request.Vote.Value.ToString().ToLower()));
|
||||
}
|
||||
|
||||
if (request.ServerID.HasValue)
|
||||
{
|
||||
formData.Add(new KeyValuePair<string, string>("ServerID", request.ServerID.Value.ToString()));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.CallFromMobile))
|
||||
{
|
||||
formData.Add(new KeyValuePair<string, string>("CallFromMobile", request.CallFromMobile));
|
||||
}
|
||||
|
||||
if (request.RecordVoice.HasValue)
|
||||
{
|
||||
formData.Add(new KeyValuePair<string, string>("RecordVoice", request.RecordVoice.Value.ToString().ToLower()));
|
||||
}
|
||||
|
||||
if (request.RecordVoiceDuration.HasValue)
|
||||
{
|
||||
formData.Add(new KeyValuePair<string, string>("RecordVoiceDuration", request.RecordVoiceDuration.Value.ToString()));
|
||||
}
|
||||
|
||||
var content = new FormUrlEncodedContent(formData);
|
||||
|
||||
var response = await httpClient.PostAsync(
|
||||
"QuickSendWithTTS",
|
||||
content,
|
||||
cancellationToken);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var jsonString = await response.Content.ReadAsStringAsync(cancellationToken);
|
||||
var result = JsonSerializer.Deserialize<QuickSendWithTTSResponse>(jsonString, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
});
|
||||
|
||||
if (result != null && !result.IsSuccess)
|
||||
{
|
||||
logger.LogWarning(
|
||||
"QuickSendWithTTS failed with ReturnValue={ReturnValue} for Number={Number}. " +
|
||||
"Error codes: -25=QuickSend disabled, 0=No permission/demo user, -2=Wrong number, " +
|
||||
"-3=Insufficient credit, -5=Text too long (>1000 chars), -6=Invalid send time, " +
|
||||
"-7/-9=TTS generation error, -8=Text too short (<3 sec), -10=Empty text, " +
|
||||
"-11=Duplicate send limit, -71=Invalid record duration, -72=No record permission, -111=Too Many Requests",
|
||||
result.ReturnValue, request.Number);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
logger.LogError(ex, "Error sending quick voice call with TTS to {Number}", request.Number);
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Unexpected error sending quick voice call with TTS");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<GetQuickSendResponse?> GetQuickSendStatusAsync(GetQuickSendRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await httpClient.PostAsJsonAsync(
|
||||
"GetQuickSend",
|
||||
request,
|
||||
cancellationToken);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<GetQuickSendResponse>(
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
logger.LogError(ex, "Error getting quick send status for {QuickSendId}", request.QuickSendId);
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Unexpected error getting quick send status");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
47
src/GreenHome.VoiceCall.Avanak/IVoiceCallService.cs
Normal file
47
src/GreenHome.VoiceCall.Avanak/IVoiceCallService.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
namespace GreenHome.VoiceCall.Avanak;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for Avanak Voice Call service
|
||||
/// </summary>
|
||||
public interface IVoiceCallService
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets account status
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Account status response</returns>
|
||||
Task<AccountStatusResponse?> GetAccountStatusAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Generates TTS (Text-to-Speech) audio from text
|
||||
/// </summary>
|
||||
/// <param name="request">TTS generation request</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>TTS generation response</returns>
|
||||
Task<GenerateTTSResponse?> GenerateTTSAsync(GenerateTTSRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Sends quick voice call with uploaded audio file
|
||||
/// </summary>
|
||||
/// <param name="request">Quick send request</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Quick send response</returns>
|
||||
Task<QuickSendResponse?> QuickSendAsync(QuickSendRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Sends quick voice call with TTS (Text-to-Speech)
|
||||
/// </summary>
|
||||
/// <param name="request">Quick send with TTS request</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Quick send with TTS response</returns>
|
||||
Task<QuickSendWithTTSResponse?> QuickSendWithTTSAsync(QuickSendWithTTSRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets quick send status
|
||||
/// </summary>
|
||||
/// <param name="request">Get quick send request</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Quick send status response</returns>
|
||||
Task<GetQuickSendResponse?> GetQuickSendStatusAsync(GetQuickSendRequest request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
263
src/GreenHome.VoiceCall.Avanak/Models.cs
Normal file
263
src/GreenHome.VoiceCall.Avanak/Models.cs
Normal file
@@ -0,0 +1,263 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace GreenHome.VoiceCall.Avanak;
|
||||
|
||||
/// <summary>
|
||||
/// Request model for AccountStatus method
|
||||
/// </summary>
|
||||
public sealed class AccountStatusRequest
|
||||
{
|
||||
// No parameters needed for AccountStatus
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response model for AccountStatus method
|
||||
/// </summary>
|
||||
public sealed class AccountStatusResponse
|
||||
{
|
||||
[JsonPropertyName("status")]
|
||||
public bool Status { get; set; }
|
||||
|
||||
[JsonPropertyName("message")]
|
||||
public string? Message { get; set; }
|
||||
|
||||
[JsonPropertyName("data")]
|
||||
public AccountStatusData? Data { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Account status data
|
||||
/// </summary>
|
||||
public sealed class AccountStatusData
|
||||
{
|
||||
[JsonPropertyName("balance")]
|
||||
public decimal? Balance { get; set; }
|
||||
|
||||
[JsonPropertyName("credit")]
|
||||
public decimal? Credit { get; set; }
|
||||
|
||||
[JsonPropertyName("expireDate")]
|
||||
public string? ExpireDate { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request model for GenerateTTS method
|
||||
/// </summary>
|
||||
public sealed class GenerateTTSRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Text to convert to speech
|
||||
/// </summary>
|
||||
[JsonPropertyName("text")]
|
||||
public required string Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Voice type (optional)
|
||||
/// </summary>
|
||||
[JsonPropertyName("voiceType")]
|
||||
public string? VoiceType { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response model for GenerateTTS method
|
||||
/// </summary>
|
||||
public sealed class GenerateTTSResponse
|
||||
{
|
||||
[JsonPropertyName("status")]
|
||||
public bool Status { get; set; }
|
||||
|
||||
[JsonPropertyName("message")]
|
||||
public string? Message { get; set; }
|
||||
|
||||
[JsonPropertyName("data")]
|
||||
public GenerateTTSData? Data { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GenerateTTS data
|
||||
/// </summary>
|
||||
public sealed class GenerateTTSData
|
||||
{
|
||||
[JsonPropertyName("messageId")]
|
||||
public string? MessageId { get; set; }
|
||||
|
||||
[JsonPropertyName("audioUrl")]
|
||||
public string? AudioUrl { get; set; }
|
||||
|
||||
[JsonPropertyName("duration")]
|
||||
public int? Duration { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request model for QuickSend method
|
||||
/// </summary>
|
||||
public sealed class QuickSendRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Recipient phone number
|
||||
/// </summary>
|
||||
[JsonPropertyName("recipient")]
|
||||
public required string Recipient { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Message ID (uploaded audio file ID)
|
||||
/// </summary>
|
||||
[JsonPropertyName("messageId")]
|
||||
public required string MessageId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response model for QuickSend method
|
||||
/// </summary>
|
||||
public sealed class QuickSendResponse
|
||||
{
|
||||
[JsonPropertyName("status")]
|
||||
public bool Status { get; set; }
|
||||
|
||||
[JsonPropertyName("message")]
|
||||
public string? Message { get; set; }
|
||||
|
||||
[JsonPropertyName("data")]
|
||||
public QuickSendData? Data { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// QuickSend data
|
||||
/// </summary>
|
||||
public sealed class QuickSendData
|
||||
{
|
||||
[JsonPropertyName("quickSendId")]
|
||||
public string? QuickSendId { get; set; }
|
||||
|
||||
[JsonPropertyName("trackingId")]
|
||||
public string? TrackingId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request model for QuickSendWithTTS method
|
||||
/// </summary>
|
||||
public sealed class QuickSendWithTTSRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Text to convert to speech and send (required)
|
||||
/// </summary>
|
||||
[JsonPropertyName("Text")]
|
||||
public required string Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Phone number (required)
|
||||
/// </summary>
|
||||
[JsonPropertyName("Number")]
|
||||
public required string Number { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enable voting option (optional)
|
||||
/// </summary>
|
||||
[JsonPropertyName("Vote")]
|
||||
public bool? Vote { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Server ID (optional, default: 0)
|
||||
/// </summary>
|
||||
[JsonPropertyName("ServerID")]
|
||||
public int? ServerID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Mobile number to add at the end of voice (optional)
|
||||
/// </summary>
|
||||
[JsonPropertyName("CallFromMobile")]
|
||||
public string? CallFromMobile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Record voice (optional)
|
||||
/// </summary>
|
||||
[JsonPropertyName("RecordVoice")]
|
||||
public bool? RecordVoice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Record voice duration (optional)
|
||||
/// </summary>
|
||||
[JsonPropertyName("RecordVoiceDuration")]
|
||||
public short? RecordVoiceDuration { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response model for QuickSendWithTTS method
|
||||
/// ReturnValue > 0 means success and contains the quickSendId
|
||||
/// </summary>
|
||||
public sealed class QuickSendWithTTSResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Return value: > 0 means success (contains quickSendId), negative values indicate errors
|
||||
/// </summary>
|
||||
[JsonPropertyName("ReturnValue")]
|
||||
public int ReturnValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// QuickSendId (when ReturnValue > 0)
|
||||
/// </summary>
|
||||
public long QuickSendId => ReturnValue > 0 ? ReturnValue : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the operation was successful
|
||||
/// </summary>
|
||||
public bool IsSuccess => ReturnValue > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request model for GetQuickSend method
|
||||
/// </summary>
|
||||
public sealed class GetQuickSendRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// QuickSend ID or Tracking ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("quickSendId")]
|
||||
public required string QuickSendId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response model for GetQuickSend method
|
||||
/// </summary>
|
||||
public sealed class GetQuickSendResponse
|
||||
{
|
||||
[JsonPropertyName("status")]
|
||||
public bool Status { get; set; }
|
||||
|
||||
[JsonPropertyName("message")]
|
||||
public string? Message { get; set; }
|
||||
|
||||
[JsonPropertyName("data")]
|
||||
public GetQuickSendData? Data { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetQuickSend data
|
||||
/// </summary>
|
||||
public sealed class GetQuickSendData
|
||||
{
|
||||
[JsonPropertyName("quickSendId")]
|
||||
public string? QuickSendId { get; set; }
|
||||
|
||||
[JsonPropertyName("trackingId")]
|
||||
public string? TrackingId { get; set; }
|
||||
|
||||
[JsonPropertyName("recipient")]
|
||||
public string? Recipient { get; set; }
|
||||
|
||||
[JsonPropertyName("status")]
|
||||
public string? Status { get; set; }
|
||||
|
||||
[JsonPropertyName("deliveryStatus")]
|
||||
public string? DeliveryStatus { get; set; }
|
||||
|
||||
[JsonPropertyName("sentAt")]
|
||||
public string? SentAt { get; set; }
|
||||
|
||||
[JsonPropertyName("deliveredAt")]
|
||||
public string? DeliveredAt { get; set; }
|
||||
|
||||
[JsonPropertyName("duration")]
|
||||
public int? Duration { get; set; }
|
||||
}
|
||||
|
||||
110
src/GreenHome.VoiceCall.Avanak/ServiceCollectionExtensions.cs
Normal file
110
src/GreenHome.VoiceCall.Avanak/ServiceCollectionExtensions.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace GreenHome.VoiceCall.Avanak;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for registering Avanak Voice Call service
|
||||
/// </summary>
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds Avanak Voice Call service to the service collection
|
||||
/// </summary>
|
||||
/// <param name="services">The service collection</param>
|
||||
/// <param name="configuration">Configuration section for AvanakVoiceCall</param>
|
||||
/// <returns>The service collection for chaining</returns>
|
||||
public static IServiceCollection AddAvanakVoiceCall(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
return services.AddAvanakVoiceCall(configuration.GetSection("AvanakVoiceCall"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds Avanak Voice Call service to the service collection
|
||||
/// </summary>
|
||||
/// <param name="services">The service collection</param>
|
||||
/// <param name="configurationSection">Configuration section for AvanakVoiceCall</param>
|
||||
/// <returns>The service collection for chaining</returns>
|
||||
public static IServiceCollection AddAvanakVoiceCall(
|
||||
this IServiceCollection services,
|
||||
IConfigurationSection? configurationSection = null)
|
||||
{
|
||||
// Configure options
|
||||
AvanakVoiceCallOptions? options = null;
|
||||
if (configurationSection != null)
|
||||
{
|
||||
options = configurationSection.Get<AvanakVoiceCallOptions>();
|
||||
}
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"AvanakVoiceCall configuration section is missing. " +
|
||||
"Please add 'AvanakVoiceCall' section to your appsettings.json with 'Token' property.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options.Token))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"AvanakVoiceCall Token is required.");
|
||||
}
|
||||
|
||||
// Register options as singleton
|
||||
services.AddSingleton(options);
|
||||
|
||||
// Register HttpClient and service
|
||||
services.AddHttpClient<IVoiceCallService, AvanakVoiceCallService>(client =>
|
||||
{
|
||||
// Ensure BaseUrl ends with / for proper relative path handling
|
||||
var baseUrl = options.BaseUrl.TrimEnd('/') + "/";
|
||||
client.BaseAddress = new Uri(baseUrl);
|
||||
// Note: Content-Type will be set automatically by HttpClient based on content type (JSON or FormUrlEncoded)
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", options.Token);
|
||||
client.Timeout = TimeSpan.FromSeconds(30);
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds Avanak Voice Call service to the service collection with explicit options
|
||||
/// </summary>
|
||||
/// <param name="services">The service collection</param>
|
||||
/// <param name="configureOptions">Action to configure options</param>
|
||||
/// <returns>The service collection for chaining</returns>
|
||||
public static IServiceCollection AddAvanakVoiceCall(
|
||||
this IServiceCollection services,
|
||||
Action<AvanakVoiceCallOptions> configureOptions)
|
||||
{
|
||||
var options = new AvanakVoiceCallOptions
|
||||
{
|
||||
Token = string.Empty // Will be set by configureOptions
|
||||
};
|
||||
configureOptions(options);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options.Token))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"AvanakVoiceCall Token is required.");
|
||||
}
|
||||
|
||||
// Register options as singleton
|
||||
services.AddSingleton(options);
|
||||
|
||||
// Register HttpClient and service
|
||||
services.AddHttpClient<IVoiceCallService, AvanakVoiceCallService>(client =>
|
||||
{
|
||||
// Ensure BaseUrl ends with / for proper relative path handling
|
||||
var baseUrl = options.BaseUrl.TrimEnd('/') + "/";
|
||||
client.BaseAddress = new Uri(baseUrl);
|
||||
// Note: Content-Type will be set automatically by HttpClient based on content type (JSON or FormUrlEncoded)
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", options.Token);
|
||||
client.Timeout = TimeSpan.FromSeconds(30);
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user