在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

这篇具有很好参考价值的文章主要介绍了在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

章节
第一章:https://www.cnblogs.com/kimiliucn/p/17662052.html
第二章:https://www.cnblogs.com/kimiliucn/p/17667200.html


在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

作者:西瓜程序猿
主页传送门:https://www.cnblogs.com/kimiliucn/


上一章节主要介绍了RocketMQ基本介绍和前期准备,以及如何创建生产者。那这一章节主要介绍一下消费端的实现、如何发布消费端,以及遇到的坑怎么去解决。


如果不知道怎么选,或者不知道怎么买云消息队列RocketMQ(阿里云版)?可以联系我[西瓜程序猿],如果需要特价购买可以通过下面地址访问:

活动地址:https://www.aliyun.com/activity?userCode=tkq1f513

在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】


四、消费端实现

4.1-创建消费者

4.1.1-创建Windows服务项目

(1)右击解决方案,然后依次点击【添加】——>【新建项目】,然后选择【 Windows 服务(.NET Framework) 】,点击下一步。

注意:Windows服务只有在.NET Framework版本中才有了,在跨平台中使用Worker Service。

在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
(2)修改项目名称,项目名称[西瓜程序猿]写的是【RocketMQ.Consumer】,然后框架选择的是【.NET Farmework 4.8】,这个可以根据自己的需要填写和选择,然后点击【创建】。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
创建好的目录如下:【Program.cs】是主程序的入口,【Service1.cs】是服务的入口,可以创建多个,然后在Prodrams.cs中配置就好了。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
(3)【Service1】服务名称可以重命名修改,此处我重命名为【RocketMQConsumerService】, Program.cs文件中也相对应的也要进行修改。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
(4)然后我们就可以在【RocketMQConsumerService】中写业务逻辑代码了,有很多种方式可以定位到要写的具体代码文件,先列举两种常用的。
方法一:在【program.cs】文件中,找到这个类,按键盘上的F12可以直接进入查看文件。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
方法二:直接右击,然后点击【查看代码】。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
业务代码写到这里面:
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
到这一步消费者服务就创建好了,然后就写具体的业务代码就行了。注意:服务必须至少重写 OnStart 和 OnStop 才有用。


4.1.2-项目依赖配置

(1)在使用Visual Studio(VS)开发.NET的应用程序和类库时,默认的目标平台为“Any CPU”。但是.NET SDK仅支持Windows 64-bit操作系统,所以需要自行设置。先右击【RocketMQ.Consumer】项目,然后点击【属性】。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
(2)点击左侧选项的【生成】,然后将目标平台改为【x64】。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(3)将资源包【ONSClient4CPP】文件夹里面所有的文件,复制到【bin/Debug】目录下。
资源包:
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
项目:
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】


4.1.3-配置日志(log4net)

(1)为了方便测试,先介绍一下如何使用log4net做日志记录,当日志启动时和停止时我们记录一下。我们在项目目录下新建一个文件夹【LogConfig】,然后再创建一个文件为【log4net.config】。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
(2)【log4net.config】内容如下。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
	<configSections>
		<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
	</configSections>

	<system.web>
		<compilation debug="true" targetFramework="4.5.2" />
		<httpRuntime targetFramework="4.5.2" />
	</system.web>
	<log4net>
		<!--错误日志:::记录错误日志-->
		<!--按日期分割日志文件 一天一个-->
		<!-- appender 定义日志输出方式   将日志以回滚文件的形式写到文件中。-->
		<appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
			<!--保存路径:下面路径项目启动的时候自动在C盘中创建log、logError文件-->
			<file value="log/error/error_" />
			<!-- 如果想在本项目中添加路径,那就直接去掉C:\\  只设置log\\LogError   项目启动中默认创建文件 -->
			<appendToFile value="true"/>
			<!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
			<rollingStyle value="Date"/>
			<!--这是按日期产生文件夹-->
			<datePattern value="yyyy-MM-dd'.log'"/>
			<!--是否只写到一个文件中-->
			<staticLogFileName value="false"/>
			<!--保留的log文件数量 超过此数量后 自动删除之前的   好像只有在 按Size分割时有效 设定值value="-1"为不限文件数-->
			<param name="MaxSizeRollBackups" value="100"/>
			<!--每个文件的大小。只在混合方式与文件大小方式下使用。超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。可用的单位:KB|MB|GB。不要使用小数,否则会一直写入当前日志-->
			<maximumFileSize value="50MB" />
			<!-- layout 控制Appender的输出格式,也可以是xml  一个Appender只能是一个layout-->
			<layout type="log4net.Layout.PatternLayout">
				<!--每条日志末尾的文字说明-->
				<!--输出格式 模板-->
				<!-- <param name="ConversionPattern"  value="记录时间:%date 线程ID:[%thread] 日志级别:%-5level 记录类:%logger   
        操作者ID:%property{Operator} 操作类型:%property{Action}%n  当前机器名:%property%n当前机器名及登录用户:%username %n  
        记录位置:%location%n 消息描述:%property{Message}%n   异常:%exception%n 消息:%message%newline%n%n" />-->

				<!--样例:2008-03-26 13:42:32,111 [10] INFO  Log4NetDemo.MainClass [(null)] - info-->
				<!--<conversionPattern value="%newline %n记录时间:%date %n线程ID:[%thread] %n日志级别: %-5level %n错误描述:%message%newline %n"/>-->
				<conversionPattern value="%n==========
                                  %n【日志级别】%-5level
                                  %n【记录时间】%date
                                  %n【执行时间】[%r]毫秒
                                  %n【出错文件】%F
                                  %n【出错行号】%L
                                  %n【出错的类】%logger 属性[%property{NDC}]
                                  %n【错误描述】%message
                                  %n【错误详情】%newline"/>
			</layout>
			<filter type="log4net.Filter.LevelRangeFilter,log4net">
				<levelMin value="ERROR" />
				<levelMax value="FATAL" />
			</filter>
		</appender>

		<!--DEBUG:::记录DEBUG日志-->
		<!--按日期分割日志文件 一天一个-->
		<!-- appender 定义日志输出方式   将日志以回滚文件的形式写到文件中。-->
		<appender name="DebugAppender" type="log4net.Appender.RollingFileAppender">
			<!--保存路径:下面路径项目启动的时候自动在C盘中创建log、logError文件-->
			<file value="log/debug/debug_" />
			<!-- 如果想在本项目中添加路径,那就直接去掉C:\\  只设置log\\LogError   项目启动中默认创建文件 -->
			<appendToFile value="true"/>
			<!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
			<rollingStyle value="Date"/>
			<!--这是按日期产生文件夹-->
			<datePattern value="yyyy-MM-dd'.log'"/>
			<!--是否只写到一个文件中-->
			<staticLogFileName value="false"/>
			<!--保留的log文件数量 超过此数量后 自动删除之前的   好像只有在 按Size分割时有效 设定值value="-1"为不限文件数-->
			<param name="MaxSizeRollBackups" value="100"/>
			<!--每个文件的大小。只在混合方式与文件大小方式下使用。超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。可用的单位:KB|MB|GB。不要使用小数,否则会一直写入当前日志-->
			<maximumFileSize value="50MB" />
			<!-- layout 控制Appender的输出格式,也可以是xml  一个Appender只能是一个layout-->
			<layout type="log4net.Layout.PatternLayout">
				<!--每条日志末尾的文字说明-->
				<!--输出格式 模板-->
				<!-- <param name="ConversionPattern"  value="记录时间:%date 线程ID:[%thread] 日志级别:%-5level 记录类:%logger   
        操作者ID:%property{Operator} 操作类型:%property{Action}%n  当前机器名:%property%n当前机器名及登录用户:%username %n  
        记录位置:%location%n 消息描述:%property{Message}%n   异常:%exception%n 消息:%message%newline%n%n" />-->

				<!--样例:2008-03-26 13:42:32,111 [10] INFO  Log4NetDemo.MainClass [(null)] - info-->
				<!--<conversionPattern value="%newline %n记录时间:%date %n线程ID:[%thread] %n日志级别: %-5level %n错误描述:%message%newline %n"/>-->
				<conversionPattern value="%n==========
                                  %n【日志级别】%-2level
                                  %n【记录时间】%date
                                  %n【执行时间】[%r]毫秒
                                  %n【debug文件】%F
                                  %n【debug行号】%L
                                  %n【debug类】%logger 属性[%property{NDC}]
                                  %n【debug描述】%message"/>
			</layout>
			<filter type="log4net.Filter.LevelRangeFilter,log4net">
				<levelMin value="DEBUG" />
				<levelMax value="WARN" />
			</filter>
		</appender>


		<!--INFO:::记录INFO日志-->
		<!--按日期分割日志文件 一天一个-->
		<!-- appender 定义日志输出方式   将日志以回滚文件的形式写到文件中。-->
		<appender name="INFOAppender" type="log4net.Appender.RollingFileAppender">
			<!--保存路径:下面路径项目启动的时候自动在C盘中创建log、logError文件-->
			<file value="log/info/info_" />
			<!-- 如果想在本项目中添加路径,那就直接去掉C:\\  只设置log\\LogError   项目启动中默认创建文件 -->
			<appendToFile value="true"/>
			<!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
			<rollingStyle value="Date"/>
			<!--这是按日期产生文件夹-->
			<datePattern value="yyyy-MM-dd'.log'"/>
			<!--是否只写到一个文件中-->
			<staticLogFileName value="false"/>
			<!--保留的log文件数量 超过此数量后 自动删除之前的   好像只有在 按Size分割时有效 设定值value="-1"为不限文件数-->
			<param name="MaxSizeRollBackups" value="100"/>
			<!--每个文件的大小。只在混合方式与文件大小方式下使用。超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。可用的单位:KB|MB|GB。不要使用小数,否则会一直写入当前日志-->
			<maximumFileSize value="50MB" />
			<!-- layout 控制Appender的输出格式,也可以是xml  一个Appender只能是一个layout-->
			<layout type="log4net.Layout.PatternLayout">
				<!--每条日志末尾的文字说明-->
				<!--输出格式 模板-->
				<!-- <param name="ConversionPattern"  value="记录时间:%date 线程ID:[%thread] 日志级别:%-5level 记录类:%logger   
        操作者ID:%property{Operator} 操作类型:%property{Action}%n  当前机器名:%property%n当前机器名及登录用户:%username %n  
        记录位置:%location%n 消息描述:%property{Message}%n   异常:%exception%n 消息:%message%newline%n%n" />-->

				<!--样例:2008-03-26 13:42:32,111 [10] INFO  Log4NetDemo.MainClass [(null)] - info-->
				<!--<conversionPattern value="%newline %n记录时间:%date %n线程ID:[%thread] %n日志级别: %-5level %n错误描述:%message%newline %n"/>-->
				<conversionPattern value="%n==========
                                  %n【日志级别】%-2level
                                  %n【记录时间】%date
                                  %n【执行时间】[%r]毫秒
                                  %n【info文件】%F
                                  %n【info行号】%L
                                  %n【info类】%logger 属性[%property{NDC}]
                                  %n【info描述】%message"/>
			</layout>
			<filter type="log4net.Filter.LevelRangeFilter,log4net">
				<levelMin value="INFO" />
				<levelMax value="WARN" />
			</filter>
		</appender>

		<!--Set root logger level to DEBUG and its only appender to A1-->
		<root>
			<!--控制级别,由低到高: ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF-->
			<level value="ALL" />
			<appender-ref ref="DebugAppender" />
			<appender-ref ref="ErrorAppender" />
			<appender-ref ref="INFOAppender" />
		</root>
	</log4net>
</configuration>

在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】(3)并且右击【log4net.config】文件,点击【属性】,然后将[复制到输出目录]设置为【始终复制】。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
(4)然后安装log4net。在项目目录中右击【引用】,然后点击【管理NuGet程序包】
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
(5)然后点击浏览,搜索【log4net】,右侧点击安装。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
(6)重要:然后配置【AssemblyInfo.cs 】文件,如果不配置,是输出不了日志的。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
添加到底部即可:(如果你的【log4net.config】文件路径和我的不一样,记得修改成跟自己配置路径一样的)。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
代码:

[assembly: log4net.Config.XmlConfigurator(ConfigFileExtension = "config", ConfigFile = "LogConfig/log4net.config", Watch = true)]

(7)在服务启动方法【OnStart】中,配置启动log4net。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
代码:

         XmlConfigurator.Configure(new System.IO.FileInfo("LogConfig/log4net.config"));

(8)然后就可以使用log4net了,首先在Windows服务中获得log4net的实例。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
代码:

private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

4.1.4-安装Nuget包

(1)右击【RocketMQ.Consumer】生产者项目,点击【引用】——>【管理NuGet程序包】。

在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(2)搜索【Kimi.RocketMQ.NET】包,然后选择最新版进行安装。

在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】


4.2-配置连接信息

(1)然后右击【RocketMQ.Consumer】项目下,点击【引用】,然后将【RocketMQ.Core】项目勾选上确定。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
(2)然后将前期准备的基本信息放在配置文件中。在【App.config】文件进行配置。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
代码:

<!--设置为云消息队列 RocketMQ 版控制台实例详情页的实例用户名。-->
<add key="ons_access_key" value="xxx" />
<!--设置为云消息队列 RocketMQ 版控制台实例详情页的实例密码。-->
<add key="ons_secret_key" value="xxx" />
<!--您在云消息队列 RocketMQ 版控制台创建的Topic。-->
<add key="ons_topic" value="XG_CXY_Test" />
<!--设置为您在云消息队列 RocketMQ 版控制台创建的Group ID。-->
<add key="ons_groupId" value="XG_CXY_Group_Test" />
<!--设置为您从云消息队列 RocketMQ 版控制台获取的接入点信息,类似“rmq-cn-XXXX.rmq.aliyuncs.com:8080”-->
<add key="ons_name_srv" value="xxx-xxx-xxx-xxx.rmq.aliyuncs.com:8080" />
<!--消费者/生产者目标来源-->
<add key="ons_client_code" value="XG_CXY_Consumer_Develop" />

(3)然后创建一个【Config】文件夹,写一个获得【ConfigSetting】配置文件的帮助类。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
代码:

    /// <summary>
    /// 配置文件
    /// </summary>
    public class ConfigGeter
    {
        private static T TryGetValueFromConfig<T>(Func<string, T> parseFunc, Func<T> defaultTValueFunc, [CallerMemberName] string key = "", string supressKey = "")
        {
            try
            {
                if (!string.IsNullOrWhiteSpace(supressKey))
                {
                    key = supressKey;
                }

                var node = ConfigurationManager.AppSettings[key];
                return !string.IsNullOrEmpty(node) ? parseFunc(node) : defaultTValueFunc();
            }
            catch (Exception ex)
            {
                return default(T);
            }
        }

        #region 消息队列:RocketMQ
        /// <summary>
        /// 设置为云消息队列 RocketMQ 版控制台实例详情页的实例用户名。
        /// </summary>
        public static string ons_access_key
        {
            get
            {
                return TryGetValueFromConfig(_ => _, () => string.Empty);
            }
        }

        /// <summary>
        /// 设置为云消息队列 RocketMQ 版控制台实例详情页的实例密码。
        /// </summary>
        public static string ons_secret_key
        {
            get
            {
                return TryGetValueFromConfig(_ => _, () => string.Empty);
            }
        }

        /// <summary>
        ///  您在云消息队列 RocketMQ 版控制台创建的Topic。
        /// </summary>
        public static string ons_topic
        {
            get
            {
                return TryGetValueFromConfig(_ => _, () => string.Empty);
            }
        }

        /// <summary>
        /// 设置为您在云消息队列 RocketMQ 版控制台创建的Group ID。
        /// </summary>
        public static string ons_groupId
        {
            get
            {
                return TryGetValueFromConfig(_ => _, () => string.Empty);
            }
        }

        /// <summary>
        /// 设置为您从云消息队列 RocketMQ 版控制台获取的接入点信息,类似“rmq-cn-XXXX.rmq.aliyuncs.com:8080”。
        /// </summary>
        public static string ons_name_srv
        {
            get
            {
                return TryGetValueFromConfig(_ => _, () => string.Empty);
            }
        }

        /// <summary>
        /// 消息来源(生产者/消费端客户端编码)
        /// </summary>
        public static string ons_client_code
        {
            get
            {
                return TryGetValueFromConfig(_ => _, () => string.Empty);
            }
        }
        #endregion
    }

4.3-封装核心代码

(1)新建一个【ConsumerStartup】文件,这个类继承自【MessageListener】类,然后实现consume方法,这个方法主要是消费者具体要执行的任务。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
代码:

/// <summary>
    /// 消费端启动
    /// </summary>
    public class ConsumerStartup : MessageListener
    {
        private readonly static ILog logger = LogManager.GetLogger(typeof(ConsumerStartup));
        private readonly static ConsumerManager manager = new ConsumerManager();
        private readonly string _consumerClientCode;
        private readonly string _ons_groupId;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="consumerClientCode">消费者客户端Code</param>
        /// <param name="ons_groupId">消费者消费的分组</param>
        public ConsumerStartup(string consumerClientCode, string ons_groupId)
        {
            _consumerClientCode = consumerClientCode;
            _ons_groupId = ons_groupId;
        }

        ~ConsumerStartup()
        {
        }

        /// <summary>
        /// 消费者任务
        /// </summary>
        /// <param name="value"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override ons.Action consume(Message value, ConsumeContext context)
        {
            Console.WriteLine("【消费者任务】:消费者消息进来了...");
            logger.Info($"【消费者任务】:消费者消息进来了...");

            string topic = value.getTopic();
            string business_id = value.getKey();
            string message_id = value.getMsgID();
            string msg_tag = value.getTag();
            byte[] bytes = Encoding.Default.GetBytes(value.getBody());
            string msg_body = Encoding.Default.GetString(bytes);
            if (string.IsNullOrEmpty(msg_body))
            {
                return ons.Action.CommitMessage;
            };

            string log_body = $"本次消费的消息:【消费序列:{value.getQueueOffset()}】【消息key:{business_id}】【消息ID:{message_id}】【Tag:{msg_tag}】";
            Console.WriteLine(log_body);
            logger.Info(log_body);
            logger.Info($"【消费内容】:{msg_body}");

            int status = 1;
            string error_msg = "";
            long sys_msg_id = 0;
            QueueOnsCommonModel consumerModel = null;

            try
            {
                //调度到具体的消费者
                consumerModel = JsonUtility.DeserializeJSON<QueueOnsCommonModel>(msg_body);
                if (consumerModel != null)
                {
                    logger.Info($"【消费者任务】:真正开始执行了(消息key:{consumerModel.MessageId})");
                    if (!long.TryParse(consumerModel.MessageId, out sys_msg_id))
                    {
                        logger.Info("sys_msg_id 转换失败!");
                    }

                    manager.ExecuteConsumer(consumerModel.Tag, consumerModel.EventType, consumerModel);

                    logger.Info($"【消费者任务】:执行完成了(消息key:{consumerModel.MessageId})");
                }
                else
                {
                    status = 2;
                    error_msg = "【调度到具体的消费者】解析消息body内容为空,无法进行消费";
                    logger.Error($"【调度到具体的消费者】解析消息body内容为空,无法进行消费");
                }
            }
            catch (Exception ex)
            {
                logger.Error($"【消费者任务】:发生异常了:{ex.Message}", ex);
                status = 2;
                error_msg = ex.Message;
            }

            return ons.Action.CommitMessage;
        }
    }

4.4-启动消费者

在【RocketMQConsumerService.cs】文件OnStart方法中创建生产者,主要就是从配置文件中获得配置信息,然后调用【QueueOnsProducer.CreatePushConsumer】方法创建消息队列生产者,通过调用【QueueOnsProducer.SetPushConsumer】方法来设置生产者,最后通过调用【QueueOnsProducer.StartPushConsumer】方法来启动生产者。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
代码:

//创建消费者
            string ons_access_key = ConfigSetting.ons_access_key;
            string ons_secret_key = ConfigSetting.ons_secret_key;
            string ons_topic = ConfigSetting.ons_topic;
            string ons_groupId = ConfigSetting.ons_groupId;
            string ons_name_srv = ConfigSetting.ons_name_srv;
            string ons_client_code = ConfigSetting.ons_client_code;
            QueueOnsProducer.CreatePushConsumer(new ONSPropertyConfigModel()
            {
                AccessKey = ons_access_key,
                SecretKey = ons_secret_key,
                Topics = ons_topic,
                GroupId = ons_groupId,
                NAMESRV_ADDR = ons_name_srv,
                OnsClientCode = ons_client_code,
            });
            //设置消费者
            QueueOnsProducer.SetPushConsumer(new ConsumerStartup(ons_client_code, ons_groupId), "*");
            //启动消费者
            QueueOnsProducer.StartPushConsumer();

4.5-接收消费消息

我们如果要创建一个具体消费者去消费某一条消息,需要先创建一个类,然后实现【IConsumerMsg】接口中的【Consume】方法。需要在这个方法上面标注两个特性,也可以是一个(意味着满足一个条件即可),一个是【ConsumerTag】Tag标签,表示要消费哪个生产的Tag标签,一个是【EventType】,表示要消费哪个生产的事件类型。如果有多个不同的消费者,就按照上面的方式创建多个即可。[西瓜程序猿]这边创建一个名为【SampleConsumer】的类作为例子。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
代码:

 /// <summary>
    /// 消费者Sample
    /// </summary>
    [ConsumerTag(QueueTagConsts.XG_Blog_Sample_Tag)]
    [EventType(QueueOnsEventType.RocketMQ_TEST)]
    public class SampleConsumer :  IConsumerMsg
    {
        private readonly static ILog logger = LogManager.GetLogger(typeof(SampleConsumer));

        public void Consume(QueueOnsCommonModel model)
        {
            logger.Info($"【西瓜程序猿-消费者Sample】:测试消费者进来了");
            if (model != null)
            {
                Console.WriteLine("tag:" + model.Tag);
                Console.WriteLine("body" + model.Body);
            }
            Console.WriteLine("【西瓜程序猿-消费者Sample】消费成功了!");
        }
    }

五、发布消费端

然后来介绍一下如何部署消费端。之前看评论区说使用NSSM部署安装Window服务更方便,后面我也试了一下确实还挺好用,但是针对目前这个程序始终运行不起来(各位大佬如果有更好的方法和建议可以在评论区提出来哈),所以这次还是用之前的方法来介绍如何部署Windows服务了。

5.1-服务基本配置

(1)点击我们的服务【RocketMQConsumerService.cs】,然后右击点击【添加安装程序】。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(2)然后可以看到下面多出来了一个文件,就是安装程序。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(3)然后可以修改基本信息,服务组件中的【服务名称】【服务描述】等等。我们右击【serviceInstall1】点击属性,然后进行修改。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(4)然后点击【serviceProcessInstall1】右击属性,进行修改。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】


5.2-服务运行与发布

当我们直接按F5或者其他方式直接运行项目时,会提示:"无法从命令行或调试程序启动服务。必须首先安装 Windows服务(使用installutil.exe),然后用ServerExplorer、Windows服务管理工具或 NET START命令启动它。"。不是这样运行的,跟着下面步骤来操作运行与发布Windows服务吧。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
前提注意:如果你设置的目标平台是x64,打开的目录会不一样,不然导致服务运行不起来。可以右击项目名,点击【属性】——>【生成】——>【目标平台】查看。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

如果不是x64版本,复制这个地址:

C:\Windows\Microsoft.NET\Framework\v4.0.30319

如果是x64版本,复制这个地址:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319

不然会报类似这种错误:在初始化安装时发生异常: System.BadImageFormatException: 未能加载文件或程序集...
(1)然后我们把上面的地址(根据自己的环境选择)添加到环境变量中。点击【控制面板】——>【系统和安全】
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(2)然后点击【系统】
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(3)点击【高级系统设置】
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(4)点击【环境变量】
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(5)在【系统变量】中找到Path,然后点击【编辑】。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(6)然后点击【新建】,然后把我们拷贝的目录复制到这里。然后点击确认即可。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(7)测试是否配置成功,输入这个命令查看一下【InstallUtil】,如果是下面这样的内容说明成功了。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(8)然后编辑解决方案和项目。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(9)以管理员身份运行cmd命令,然后安装服务。

InstallUtil 项目启动执行文件全路径

西瓜程序猿的例子:

InstallUtil D:\项目演示临时保存\MyDemoService\MyDemoService\bin\Debug\MyDemoService.exe

在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(10)出现这个说明安装成功了。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(11)打开服务管理器,找到要启动的服务,然后右击启动服务。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】

(12)如果要卸载服务,可以运行这个命令:

InstallUtil /u 项目启动执行文件全路径

西瓜程序猿的例子:

InstallUtil /u D:\项目演示临时保存\MyDemoService\MyDemoService\bin\Debug\MyDemoService.exe

在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】


5.3-常见命令

1、安装服务:InstallUtil 项目启动执行文件全路径
2、启动服务:net start 服务名
3、停止服务:net stop 服务名
4、卸载服务:InstallUtil /u 项目启动执行文件全路径


5.4-测试消费消息

(1)首先可以先看一下日志,看一下这个消费者服务是否启动成功了。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
(2)然后再日志里面记录下消费的消费,在根据消息Key或者消息ID在阿里云后台查询一下这一条消息的【消息轨迹】,如果提示消费成功就说明确实已经进行消费了。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
最后,还有可能会出现消息生产失败、消息消费失败等场景,大佬们可以根据实际情况进行设计和跳转哈。


六、防踩坑指南

5.1:ons.ONSClient4CPPPINVOKE的类型初始值设定项引发异常

异常详情:

“ons.ONSClient4CPPPINVOKE”的类型初始值设定项引发异常。

解决方案:
第一步:在使用Visual Studio(VS)开发.NET的应用程序和类库时,默认的目标平台为“Any CPU”。但是.NET SDK仅支持Windows 64-bit操作系统,所以需要自行设置。先右击【RocketMQ.Producer】项目,然后点击【属性】,点击左侧选项的【生成】,然后将目标平台改为【x64】。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
第二步:将资源包【ONSClient4CPP】文件夹里面所有的文件,复制到【bin】目录下。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】


5.2:Topic Route does not exist

异常详情:

Topic Route does not exist, Topic:XG_CXY_Test exception:msg: No route info of this topic, ,error:-1,in file <..\src\producer\DefaultMQProducer.cpp> line:581
See https://github.com/alibaba/ons/issues/7 for further details.”

异常截图:
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
解决方案:
这个问题一般是没有链接上RocketMQ,检查一下配置文件中信息是否与RocketMQ信息一致。尤其是[ons_name_srv] RocketMQ 版控制台获取的接入点信息,类似“rmq-cn-XXXX.rmq.aliyuncs.com:8080”切记不要加"http://或者https😕/"。我这边也经常遇到这个问题,因为只设置了【VPC专有网络】访问,也就是说在本地访问不了RocketMQ,只能在服务器内网访问。


5.3:官方文档仅作为参考

吐槽一下云消息队列RocketMQ(阿里云版)的官方文档,看下来对.NET开发同学不太友好,仅指的是老版本。看文档做开发的时候看了很多有时候发现下载下来的案例代码和文档上线写的代码不一致。然后文档上面看的是.NET SDK示例代码,出现的却是别的 C++语言代码。
在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】


我是西瓜程序猿,感谢大家的阅读和支持。编写不易,如果对大家有帮助,用您发财的小手点个赞和关注呗,非常感谢!有问题欢迎联系我一起学习与探讨~


开源地址:

Gitee:https://gitee.com/kimiliucn/Kimi.RocketMQ.NET
GitHub:https://github.com/kimiliucn/Kimi.RocketMQ.NET


上一章节:https://www.cnblogs.com/kimiliucn/p/17662052.html

原文链接:https://www.cnblogs.com/kimiliucn/p/17667200.html文章来源地址https://www.toymoban.com/news/detail-681973.html

到了这里,关于在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 阿里云弹性云桌面安装失败问题解决记录(.net framework 4.6.2 or later:Error Code: 12029)

    1,问题 图像显示客户端安装错误     然后我就手动下载了,这个文件 下载好之后是这个文件     然后安装一下就报了这个错误 .net framework 4.6.2 or later:Error Code: 12029 这个问题是.net framework 4.6.2文件有问题,把他重新安装就好了 然后又发现.net framework 4.6.2安装不了 解决了这个

    2024年02月06日
    浏览(42)
  • RabbitMQ+SpringBoot企业版队列实战------【华为云版】

    安装Erlang 官网提示:https://www.erlang-solutions.com/resources/download.html 检测erlang 安装RabbitMQ  文件下载 官网下载地址:

    2024年02月07日
    浏览(35)
  • Redis+SpringBoot企业版集群实战------【华为云版】

      目录 安装 复制及集群 bgsave  rdb aof SpringBoot+Redis操作 操作string 操作hash 操作set 操作sorted set 获取所有key删除 设置key的失效时间 SpringDataRedis整合使用哨兵机制 下载地址 Redis 上传至服务器  解压 安装依赖  预编译 切换到解压目录 创建安装目录 不使用: make install (make in

    2024年02月12日
    浏览(40)
  • 黑马程序员rocketmq第二章

    maven工程springboot-rocketmq-producer application.properties 测试类 springboot-rocketmq-consumer application.properties zookeeper集群搭建 1.在/usr/soft/zookeeper-cluster下存放zookeeper-3.4.6.tar.gz 2.解压:tar -zvxf zookeeper-3.4.6.tar.gz 3./usr/soft/zookeeper-cluster/zookeeper-3.4.6/conf 下重命名 zoo_sample.cfg为zoo.cfg mv zoo_sample.cf

    2023年04月26日
    浏览(87)
  • 【C#】.Net Framework框架使用JWT

    2023年,第31周,第2篇文章。给自己一个目标,然后坚持总会有收货,不信你试试! 本篇文章主要简单讲讲,.Net Framework框架下使用JWT的代码例子,以及他们的基本概念。 2002年微软发布了.net framework 1.0,那个时候博主刚开始玩传奇游戏,接触电脑的时间还是挺早的。 JWT(JS

    2024年02月15日
    浏览(57)
  • .Net Framework使用Autofac实现依赖注入

    最近也是找了快2周的工作了,收到的面试邀请也就几个,然后有个面试题目是用asp.net mvc + Entityframework 做一个学生信息增删改查系统。因为题目要求了用Entityframework 也就是EF 那也就不上core了,web项目也是用Framework 4.8去做的。 本文的重点是IOC容器,在Framework 中是没有自带的

    2024年02月09日
    浏览(46)
  • .net framework 命令行项目使用 sqlite,DbContext

    以我的环境举例 .net framwordk = 4.7.2 新建项目 Nuget包安装 EntityFramework:数据库框架 SQLite.CodeFirst:实体对象转换为数据库映射关系 System.Data.SQLite:sqlite数据库操作 Tips:SQLite内置安装包,安装该nuget回自动安装多个配套程序集 安装结果 三者之间的关系 EF:ORM操作框架,但不包括数据

    2024年02月09日
    浏览(33)
  • WebRTC实战-第二章-使用WebRTC实现音视频通话

    、 什么是WebRTC|WebRTC入门到精通必看|快速学会音视频通话原理|WebRTC超全资料分享FFmpeg/rtmp/hls/rtsp/SRS WebRTC **WebRTC详细指南** http://www.vue5.com/webrtc/webrtc.html WEBRTC三种类型(Mesh、MCU 和 SFU)的多方通信架构 WebRTC API包括媒体捕获,音频和视频编码和解码,传输层和会话管理 。 假设

    2023年04月12日
    浏览(53)
  • 使用try-convert将.NET Framework项目迁移到.NET Core

    工具地址:GitHub - dotnet/try-convert:帮助 .NET 开发人员将他们的项目移植到 .NET Core! 这是一个简单的工具,有助于将.NET Framework项目迁移到.NET Core。 在此处将其作为全局工具安装:   如果您已经安装了它,请确保更新:   如果您再次使用该工具,请确保您使用的是最新版本:

    2024年02月08日
    浏览(40)
  • 【C#】.Net Framework框架下使用SQLike以及基本概念

    2023年,第32周,第2篇文章。给自己一个目标,然后坚持总会有收货,不信你试试! 在C#的.NET Framework框架下,有很多轻量级数据库选择,比如:SQLike就是其中一款,一起来了解SQLike的简单使用吧。 轻量级数据库是指具有较小的存储需求、资源消耗较低、易于部署和使用的数据

    2024年02月11日
    浏览(79)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包