首页 > 其他分享 >orchard core 2.02 的模块 学习1 实践:创建阿里云sms模块

orchard core 2.02 的模块 学习1 实践:创建阿里云sms模块

时间:2024-10-17 08:59:10浏览次数:1  
标签:core orchard siteService message settings 模块 new model public

1、手动创建
2、命令行从模板创建

手动创建就是复制一个官方的任意模块。
这个不细说。

2、我是从命令行创建的。 首先要安装orchard core的模板
dotnet new install OrchardCore.ProjectTemplates::2.0.2

参考: https://docs.orchardcore.net/en/latest/getting-started/templates/

在自己项目的文件夹 运行cmd命令 ,然后执行创建一个新的模块 : Super.Aliyun.SMS

模板可以选择 ocmodulecms 跟ocmodulemvc 前者是cms的模块,后者是mvc的。 cms自带一些基础的路由
然后在vs的项目 添加该模块,以下是创建的默认文件:

可以修改 Manifest.cs (清单)的内容,比如 作者,还有功能名称。
默认的访问路径是: 模块名称/控制器/方法
我这边创建的是 Super.Aliyun.SMS
所以默认是
http://localhost:5111/Super.Aliyun.SMS/Home/Index

现在开始。
引入orchardcore的sms模块

接下去只要实现阿里云的sms服务,按官方的说明:
要实现自己想要的
services.AddSmsProviderOptionsConfiguration<YourCustomImplemenation>()
`public class TwilioProviderOptionsConfigurations : IConfigureOptions
{
private readonly ISiteService _siteService;

public TwilioProviderOptionsConfigurations(ISiteService siteService)
{
    _siteService = siteService;
}

public void Configure(SmsProviderOptions options)
{
    var typeOptions = new SmsProviderTypeOptions(typeof(TwilioSmsProvider));

    var site = _siteService.GetSiteSettingsAsync().GetAwaiter().GetResult();
    var settings = site.As<TwilioSettings>();

    typeOptions.IsEnabled = settings.IsEnabled;

    options.TryAddProvider(TwilioSmsProvider.TechnicalName, typeOptions);
}

}所以我们要添加 阿里云短信的相关配置。 public class AliyunProviderOptionsConfigurations : IConfigureOptions
{
private readonly ISiteService _siteService;

  public AliyunProviderOptionsConfigurations(ISiteService siteService)
  {
      _siteService = siteService;
  }

  public void Configure(SmsProviderOptions options)
  {
      var typeOptions = new SmsProviderTypeOptions(typeof(TwilioSmsProvider));

      var site = _siteService.GetSiteSettingsAsync().GetAwaiter().GetResult();
      var settings = site.As<TwilioSettings>();

      typeOptions.IsEnabled = settings.IsEnabled;

      options.TryAddProvider(TwilioSmsProvider.TechnicalName, typeOptions);
  }

}添加AliyunProviderOptionsConfigurations ublic class AliyunProviderOptionsConfigurations : IConfigureOptions
{
private readonly ISiteService _siteService;

    public AliyunProviderOptionsConfigurations(ISiteService siteService)
    {
        _siteService = siteService;
    }

    public void Configure(SmsProviderOptions options)
    {
        var typeOptions = new SmsProviderTypeOptions(typeof(AliyunSmsProvider));

        //var site = _siteService.GetSiteSettingsAsync().GetAwaiter().GetResult();
        //var settings = site.As<AliyunSettings>();
        var settings = _siteService.GetSettingsAsync<AliyunSettings>()
.GetAwaiter()
.GetResult();

        typeOptions.IsEnabled = settings.IsEnabled;

        options.TryAddProvider(AliyunSmsProvider.TechnicalName, typeOptions);
    }
}`

添加aliyunsettings 跟aliyunsmsprovider
` public class AliyunSmsProvider : ISmsProvider
{
public const string TechnicalName = "Aliyun";

 public const string ProtectorName = "Aliyun";

 private static readonly JsonSerializerOptions _jsonSerializerOptions = new JsonSerializerOptions {
     PropertyNamingPolicy = SnakeCaseNamingPolicy.Instance
 };

 private readonly ISiteService _siteService;

 private readonly IDataProtectionProvider _dataProtectionProvider;

 private readonly ILogger<AliyunSmsProvider> _logger;

 private readonly IHttpClientFactory _httpClientFactory;

 protected readonly IStringLocalizer S;

 private AliyunSettings _settings;

 public LocalizedString Name => S["Aliyun"];

 public AliyunSmsProvider(ISiteService siteService, IDataProtectionProvider dataProtectionProvider, ILogger<AliyunSmsProvider> logger, IHttpClientFactory httpClientFactory, IStringLocalizer<AliyunSmsProvider> stringLocalizer)
 {
     _siteService = siteService;
     _dataProtectionProvider = dataProtectionProvider;
     _logger = logger;
     _httpClientFactory = httpClientFactory;
     S = stringLocalizer;
 }

 public async Task<SmsResult> SendAsync(SmsMessage message)
 {
     ArgumentNullException.ThrowIfNull(message, "message");
     if (string.IsNullOrEmpty(message.To)) {
         throw new ArgumentException("A phone number is required in order to send a message.");
     }

     if (string.IsNullOrEmpty(message.Body)) {
         throw new ArgumentException("A message body is required in order to send a message.");
     }

     try {
         AliyunSettings aliyunSettings = await GetSettingsAsync();

         var request = new SendSmsRequest {
             PhoneNumbers = message.To,
             SignName = aliyunSettings.SignName,
             TemplateCode = aliyunSettings.TemplateCode,
             TemplateParam = message.Body
         };


         var aliyunclient = CreateClient(aliyunSettings);
         //var response = await aliyunclient.SendSmsAsync(request);
        SendSmsRequest sendSmsRequest = new SendSmsRequest {
             PhoneNumbers = message.To,
             SignName = aliyunSettings.SignName,
         };
          var response = await  aliyunclient.SendSmsAsync(sendSmsRequest);

         //try {
         //    // 复制代码运行请自行打印 API 的返回值
         //    aliyunclient.SendSmsWithOptions(sendSmsRequest, new AlibabaCloud.TeaUtil.Models.RuntimeOptions());
         //} catch (TeaException error) {
         //    // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
         //    // 错误 message
         //    Console.WriteLine(error.Message);
         //    // 诊断地址
         //    Console.WriteLine(error.Data["Recommend"]);
         //    AlibabaCloud.TeaUtil.Common.AssertAsString(error.Message);
         //} catch (Exception _error) {
         //    TeaException error = new TeaException(new Dictionary<string, object>
         //    {
         //    { "message", _error.Message }
         //});
         //    // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
         //    // 错误 message
         //    Console.WriteLine(error.Message);
         //    // 诊断地址
         //    Console.WriteLine(error.Data["Recommend"]);
         //    AlibabaCloud.TeaUtil.Common.AssertAsString(error.Message);
         //}
         if (response.StatusCode == 200) {
             return SmsResult.Success;
         } else {
             _logger.LogError("Aliyun SMS service was unable to send SMS messages. Error code: {errorCode}, message: {errorMessage}", response.StatusCode, response.Body);
             return SmsResult.Failed(S["SMS message was not send."]);
         }


     } catch (Exception ex) {
         _logger.LogError(ex, "Twilio service was unable to send SMS messages.");
         return SmsResult.Failed(S["SMS message was not send. Error: {0}", new object[1] { ex.Message }]);
     }
   //  return SmsResult.Failed(S["SMS message was not send. Error: {0}", new object[1] { "未配置" }]);

 }
 /// <summary>
 /// 返回请求客户端 根据具体的实现
 /// </summary>
 /// <param name="settings"></param>
 /// <returns></returns>
 private HttpClient GetHttpClient(AliyunSettings settings)
 {
     string s = settings.AccessKeyId + ":" + settings.AccessKeySecret;
     string parameter = Convert.ToBase64String(Encoding.ASCII.GetBytes(s));
     HttpClient httpClient = _httpClientFactory.CreateClient("Aliyun");
     httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", parameter);
     return httpClient;
 }
 public static  Client CreateClient(AliyunSettings settings)
 {
     // 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考。
     // 建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378671.html。
     AlibabaCloud.OpenApiClient.Models.Config config = new AlibabaCloud.OpenApiClient.Models.Config {
         // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
         AccessKeyId = settings.AccessKeyId,
         // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
         AccessKeySecret = settings.AccessKeySecret,
     };
     // Endpoint 请参考 https://api.aliyun.com/product/Dysmsapi
     config.Endpoint = "dysmsapi.aliyuncs.com";
     return new AlibabaCloud.SDK.Dysmsapi20170525.Client(config);
 }
 /// <summary>
 /// 获取设置
 /// </summary>
 /// <returns></returns>
 private async Task<AliyunSettings> GetSettingsAsync()
 {
     if (_settings == null) {
         AliyunSettings aliyunSettings = await _siteService.GetSettingsAsync<AliyunSettings>();
         IDataProtector protector = _dataProtectionProvider.CreateProtector("Aliyun");
         _settings = new AliyunSettings {
             AccessKeyId = aliyunSettings.AccessKeyId,
             AccessKeySecret = aliyunSettings.AccessKeySecret,
             SignName = aliyunSettings.SignName,
             TemplateCode=   aliyunSettings.TemplateCode,
         };
     }

     return _settings;
 }

}对应添加 driver 还有视图 public class AliyunSettingsDisplayDriver : SiteDisplayDriver
{
private readonly IShellReleaseManager _shellReleaseManager;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IAuthorizationService _authorizationService;
private readonly IPhoneFormatValidator _phoneFormatValidator;
private readonly IDataProtectionProvider _dataProtectionProvider;
private readonly INotifier _notifier;

  internal readonly IHtmlLocalizer H;
  internal readonly IStringLocalizer S;

  protected override string SettingsGroupId
      => SmsSettings.GroupId;

  public AliyunSettingsDisplayDriver(
      IShellReleaseManager shellReleaseManager,
      IHttpContextAccessor httpContextAccessor,
      IAuthorizationService authorizationService,
      IPhoneFormatValidator phoneFormatValidator,
      IDataProtectionProvider dataProtectionProvider,
      INotifier notifier,
      IHtmlLocalizer<AliyunSettingsDisplayDriver> htmlLocalizer,
      IStringLocalizer<AliyunSettingsDisplayDriver> stringLocalizer)
  {
      _shellReleaseManager = shellReleaseManager;
      _httpContextAccessor = httpContextAccessor;
      _authorizationService = authorizationService;
      _phoneFormatValidator = phoneFormatValidator;
      _dataProtectionProvider = dataProtectionProvider;
      _notifier = notifier;
      H = htmlLocalizer;
      S = stringLocalizer;
  }

  public override IDisplayResult Edit(ISite site, AliyunSettings settings, BuildEditorContext c)
  {
      return Initialize<AliyunSettingsViewModel>("AliyunSettings_Edit", model => {
          model.IsEnabled = settings.IsEnabled;
          model.AccessKeyId = settings.AccessKeyId;
          model.AccessKeySecret = settings.AccessKeySecret;
          model.SignName = settings.SignName;
          model.TemplateCode = settings.TemplateCode;
      }).Location("Content:5#Aliyun")
      .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, SmsPermissions.ManageSmsSettings))
      .OnGroup(SettingsGroupId);
  }

  public override async Task<IDisplayResult> UpdateAsync(ISite site, AliyunSettings settings, UpdateEditorContext context)
  {
      var user = _httpContextAccessor.HttpContext?.User;

      if (!await _authorizationService.AuthorizeAsync(user, SmsPermissions.ManageSmsSettings)) {
          return null;
      }

      var model = new AliyunSettingsViewModel();

      await context.Updater.TryUpdateModelAsync(model, Prefix);
      var hasChanges = settings.IsEnabled != model.IsEnabled;
      var smsSettings = site.As<SmsSettings>();

      if (!model.IsEnabled) {
          if (hasChanges && smsSettings.DefaultProviderName == TwilioSmsProvider.TechnicalName) {
              await _notifier.WarningAsync(H["You have successfully disabled the default SMS provider. The SMS service is now disable and will remain disabled until you designate a new default provider."]);

              smsSettings.DefaultProviderName = null;

              site.Put(smsSettings);
          }

          settings.IsEnabled = false;
      } else {
          settings.IsEnabled = true;

          if (string.IsNullOrWhiteSpace(model.AccessKeyId)) {
              context.Updater.ModelState.AddModelError(Prefix, nameof(model.AccessKeyId), S["accessKeyId requires a value."]);
          }

          if (string.IsNullOrWhiteSpace(model.AccessKeySecret)) {
              context.Updater.ModelState.AddModelError(Prefix, nameof(model.AccessKeySecret), S["AccessKeySecret requires a value."]);
          }

          if (settings.SignName == null && string.IsNullOrWhiteSpace(model.SignName)) {
              context.Updater.ModelState.AddModelError(Prefix, nameof(model.SignName), S["SignName required a value."]);
          }
         
          // Has change should be evaluated before updating the value.
          hasChanges |= settings.AccessKeyId != model.AccessKeyId;
          hasChanges |= settings.AccessKeySecret != model.AccessKeySecret;
          hasChanges |= settings.SignName != model.SignName;
          hasChanges |= settings.TemplateCode != model.TemplateCode;

          settings.AccessKeyId = model.AccessKeyId;
          settings.AccessKeySecret = model.AccessKeySecret;
          settings.SignName = model.SignName;
          settings.TemplateCode = model.TemplateCode;

      }

      if (context.Updater.ModelState.IsValid && settings.IsEnabled && string.IsNullOrEmpty(smsSettings.DefaultProviderName)) {
          // If we are enabling the only provider, set it as the default one.
          smsSettings.DefaultProviderName = AliyunSmsProvider.TechnicalName;
          site.Put(smsSettings);
          hasChanges = true;
      }

      if (hasChanges) {
          _shellReleaseManager.RequestRelease();
      }

      return Edit(site, settings, context);
  }

}`

`@using OrchardCore.Sms.Services
@using OrchardCore.Sms.ViewModels
@using OrchardCore.Sms
@using Super.Aliyun.SMS.ViewModels

@model AliyunSettingsViewModel

<h4>@T["Aliyun Account Info"]</h4>
<div class="mb-3" asp-validation-class-for="AccessKeyId">
    <label asp-for="AccessKeyId" class="form-label">@T["AccessKeyId"]</label>
    <input asp-for="AccessKeyId" class="form-control" />
    <span asp-validation-for="AccessKeyId"></span>
    <span class="hint">@T["AccessKeyId must include a country code."]</span>
</div>

<div class="mb-3" asp-validation-class-for="AccessKeySecret">
    <label asp-for="AccessKeySecret" class="form-label">@T["AccessKeySecret"]</label>
    <input asp-for="AccessKeySecret" class="form-control" />
    <span asp-validation-for="AccessKeySecret"></span>
    <span class="hint">@T["AccessKeySecret must include a country code."]</span>
</div>
<div class="mb-3" asp-validation-class-for="SignName">
    <label asp-for="SignName" class="form-label">@T["SignName"]</label>
    <input asp-for="SignName" class="form-control" />
    <span asp-validation-for="SignName"></span>
</div>
<div class="mb-3" asp-validation-class-for="TemplateCode">
    <label asp-for="TemplateCode" class="form-label">@T["TemplateCode"]</label>
    <input asp-for="TemplateCode" class="form-control" />
    <span asp-validation-for="TemplateCode"></span>
</div>
`

修改starup.cs 添加
` public override void ConfigureServices(IServiceCollection services)
{

 services.AddSmsProvider<AliyunSmsProvider>("Aliyun");
 services.AddSmsProviderOptionsConfiguration<AliyunProviderOptionsConfigurations>()
     .AddSiteDisplayDriver<AliyunSettingsDisplayDriver>();            ;

}`
web项目添加引用, 然后运行 添加功能

标签:core,orchard,siteService,message,settings,模块,new,model,public
From: https://www.cnblogs.com/zxs-onestar/p/18471353

相关文章

  • import torch OSError: [WinError 126] 找不到指定的模块。
    importtorch报错,信息如下:OSError:[WinError126]找不到指定的模块。Errorloading"C:\Anaconda3\envs\python-3.11\Lib\site-packages\torch\lib\shm.dll"oroneofitsdependencies.我的pytorch版本pipinstalltorch==2.3.0torchvision==0.18.0torchaud......
  • CorelDRAW (CDR) 25.2.0.301最新破解版安装包下载
    CorelDRAWGraphicsSuite简称cdr,是一款备受关注的矢量制图及设计软件,这次重大更新不仅是CorelDRAW在36年创新历史中的又一重要里程碑,也展示了其在设计软件领域持续创新和卓越性能的领导地位。作为全球历史最悠久且功能最为强大的图形与图像编辑软件之一,CorelDRAW以其专业......
  • 负载均衡和反向代理区别和nginx负载均衡模块
    目录负载均衡和反向代理区别相似之处:区别:负载均衡和反向代理使用什么服务 nginx的负载均衡模块 ​编辑负载均衡和反向代理区别相似之处:请求分发:两者都可以将客户端的请求分发到多个后端服务器,以提高系统的处理能力。提高性能:它们都有助于提高网络服务的性能,通过......
  • Idea序列图插件-SequenceDiagram Core
    简介SequenceDiagramCore是一个IntelliJIDEA插件,它允许开发者直接在IDE中创建和编辑序列图(SequenceDiagrams)。序列图是UML(统一建模语言)中的一种图表类型,用于描述对象之间如何交互以及这些交互的顺序。这种类型的图表对于理解复杂的系统流程、设计模式或者组件之间......
  • 使用宝塔面板一键部署.NET Core
    都2024年了,搜了一下网上关于在宝塔上部署.netCore项目的,基本还是五六年前那一套: supervisor守护进程启动项目+ 新增静态站点+手动配置反向代理全套下来也挺麻烦的........前几天在一台闲置主机上安装了个宝塔面板版本是:9.0  发现网站选项里多了很多选项,万恶的是居......
  • YOLOv11改进策略【卷积层】| ICCV-2023 SAFM 空间自适应特征调制模块 对C3k2进行二次
    一、本文介绍本文记录的是利用空间自适应特征调制模块SAFM优化YOLOv11的目标检测方法研究。SAFM通过更好地利用特征信息来实现模型性能和效率的平衡。本文通过二次创新C3k2,能够动态选择代表性特征,并结合局部上下文信息,提升模型的检测精度。专栏目录:YOLOv11改进目录一览......
  • 优惠券秒杀模块方案设计
    本文章针对优惠券秒杀场景所进行的方案设计,考虑不周的地方,烦请指正。在我们兑换/秒杀优惠券模板的接口中,可能会存在以下三个难点:-高并发流量压力:秒杀活动往往会瞬间吸引大量用户访问系统,导致流量骤增,如果直接访问数据库,可能会让数据库负载过重,甚至导致宕机。-库存超卖问题:由......
  • coredata类比
    在CoreData中,理解各个类和它们之间关系的方式,可以通过类比现实生活中的物品和概念来帮助理解。以下是CoreData中一些主要类的类比:1.NSManagedObjectContext类比:一个“工作空间”或“办公室”解释:就像一个办公室是你处理工作、进行交流的地方,NSManagedObjectContext是......
  • 第九章习题3-编写一个函数print,打印一个学生的成绩数组,该数组有5个学生的数据记录,每个
     ......
  • 基于FPGA的16PSK调制解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不
    1.算法仿真效果VIVADO2019.2仿真结果如下(完整代码运行后无水印): 设置SNR=30db      设置SNR=20db:     系统RTL结构图如下:   2.算法涉及理论知识概要       十六进制相位移键控(16PSK,16-PhaseShiftKeying)是一种数字调制技术,它通......