Practical use of RocketMQ (Alibaba Cloud version) in .NET Framework [Chapter 2]

Table of contents

4. Consumer side implementation

4.1-Create a consumer

4.1.1-Create Windows Service Project

4.1.2-Project dependency configuration

4.1.3-Configuration log (log4net)

4.2-Configure connection information

4.3-Encapsulating core code

4.4-Start the consumer

4.5-Receive consumption messages

5. Release the consumer side

5.1-Basic configuration of service

5.2-Service operation and release

5.3-Common commands

5.4-Test consuming messages

6. Guide to preventing pitfalls

5.1: Type initializer for ons.ONSClient4CPPPINVOKE throws exception

5.2:Topic Route does not exist

5.3: Official documents are for reference only


chapter

Chapter 1:Practical use of RocketMQ (Alibaba Cloud version) in .NET Framework [Chapter 1]_Xigua Programmer’s Blog-CSDN Blog

Chapter 2:Practical use of RocketMQ (Alibaba Cloud version) in .NET Framework [Chapter 2]_Xigua Programmer’s Blog-CSDN Blog

Author: Xigua Programmer

Homepage Portal:Xigua Programmer_ASP.NET Core,ASP.NET,Database-CSDN Blog

The previous chapter mainly introduced the basic introduction and preliminary preparation of RocketMQ, as well as how to create a producer. This chapter mainly introduces the implementation of the consumer end, how to release the consumer end, and how to solve the pitfalls encountered.

 If you don’t know how to choose, or don’t know how to buy the cloud message queue RocketMQ (Alibaba Cloud version)? You can contact me [Xigua Programmer]. If you need to buy at a special price, you can visit the following address:

Activity site:Government site

4. Consumer side implementation

4.1-Create a consumer

4.1.1-Create Windows Service Project

(1) Right-click the solution, then click [Add] -> [New Project], then select [Windows Service (.NET Framework)], and click Next.

Note: Windows services are only available in the .NET Framework version, use Worker Service in cross-platform.

(2) Modify the project name. The project name [Xigua Programmer] writes [RocketMQ.Consumer], and then the framework selection is [.NET Farmework 4.8]. You can fill in and select this according to your own needs, and then click [Create] .

The created directory is as follows: [Program.cs] is the entrance to the main program, and [Service1.cs] is the entrance to the service. You can create multiple ones and then configure them in Prodrams.cs.

(3) The [Service1] service name can be renamed and modified. Here I renamed it to [RocketMQConsumerService], and the corresponding modifications are also required in the Program.cs file.

(4) Then we can write business logic code in [RocketMQConsumerService]. There are many ways to locate the specific code file to be written. Let’s list two commonly used ones first.

Method 1: In the [program.cs] file, find this class and press F12 on the keyboard to directly enter the file.

Method 2: Right-click directly and click [View Code].

The business code is written here:

At this point, the consumer service has been created, and then you just need to write the specific business code. Note: Services must override at least OnStart and OnStop to be useful.

4.1.2-Project dependency configuration

(1) When using Visual Studio (VS) to develop .NET applications and class libraries, the default target platform is "Any CPU". However, the .NET SDK only supports Windows 64-bit operating system, so you need to set it up yourself. First right-click the [RocketMQ.Consumer] project, and then click [Properties].

(2) Click [Generate] on the left option, and then change the target platform to [x64].

(3) Copy all files in the resource package [ONSClient4CPP] folder to the [bin/Debug] directory.

Resource pack:

project:

4.1.3-Configuration log (log4net)

(1) In order to facilitate testing, let's first introduce how to use log4net for logging. We will record when the log starts and stops. We create a new folder [LogConfig] in the project directory, and then create a file [log4net.config].

(2) The content of [log4net.config] is as follows.

<?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>

(3) And right-click the [log4net.config] file, click [Properties], and then set [Copy to Output Directory] to [Always Copy].

(4) Then install log4net. Right-click [References] in the project directory, and then click [Manage NuGet Packages]

(5) Then click Browse, search for [log4net], and click Install on the right side.

(6) Important: Then configure the [AssemblyInfo.cs] file. If you do not configure it, the log will not be output.

Just add it to the bottom: (If your [log4net.config] file path is different from mine, remember to change it to the same as your own configuration path).

Code:

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

(7) In the service startup method [OnStart], configure to start log4net.

Code:

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

(8) Then you can use log4net. First obtain an instance of log4net in the Windows service.

Code:

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

4.1.4-Install Nuget package

(1) Right-click the [RocketMQ.Consumer] producer project, click [Reference] -> [Manage NuGet Package].

(2) Search for the [Kimi.RocketMQ.NET] package, and then select the latest version to install.

4.2-Configure connection information

(1) Then right-click under the [RocketMQ.Consumer] project, click [Reference], and then check the [RocketMQ.Core] project and confirm.

(2) Then put the basic information prepared in the early stage in the configuration file. Configure in the [App.config] file.

Code:

<!--设置为云消息队列 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) Then create a [Config] folder and write a helper class to obtain the [ConfigSetting] configuration file.

Code:

    /// <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-Encapsulating core code

(1) Create a new [ConsumerStartup] file. This class inherits from the [MessageListener] class, and then implements the consume method. This method is mainly the specific task to be performed by the consumer.

Code:

/// <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-Start the consumer

Create a producer in the OnStart method of the [RocketMQConsumerService.cs] file. The main purpose is to obtain the configuration information from the configuration file, then call the [QueueOnsProducer.CreatePushConsumer] method to create a message queue producer, and set the producer by calling the [QueueOnsProducer.SetPushConsumer] method. , and finally start the producer by calling the [QueueOnsProducer.StartPushConsumer] method.

Code:

//创建消费者
            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-Receive consumption messages

If we want to create a specific consumer to consume a certain message, we need to first create a class and then implement the [Consume] method in the [IConsumerMsg] interface. Two characteristics need to be marked on this method, which can also be one (meaning that one condition is met). One is the [ConsumerTag] Tag, which indicates which produced Tag to consume, and the other is [EventType], which indicates that it is to be consumed. Which event type is produced. If there are multiple different consumers, just create multiple ones as above. [Xigua Programmer] Here we create a class named [SampleConsumer] as an example.

Code:

 /// <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】消费成功了!");
        }
    }

5. Release the consumer side

Then let’s introduce how to deploy the consumer side. I read in the comment area that it is more convenient to use NSSM to deploy and install Window services. I also tried it later and it was indeed very easy to use. However, the current program still cannot run. (If you have better methods and suggestions, you can leave them in the comments. District brought it up), so this time I will use the previous method to introduce how to deploy Windows services.

5.1-Basic configuration of service

(1) Click on our service [RocketMQConsumerService.cs], then right-click and click [Add Installer].

(2) Then you can see an extra file below, which is the installation program.

(3) Then you can modify the basic information, [Service Name] [Service Description] and so on in the service component. We right-click [serviceInstall1], click Properties, and then modify it.

(4) Then click [serviceProcessInstall1], right-click the properties, and modify it.

5.2-Service operation and release

When we press F5 or run the project directly in other ways, we will be prompted: "The service cannot be started from the command line or debugger." You must first install the Windows service (using installutil.exe) and then start it using Server Explorer, the Windows Service Management Tool, or the NET START command. ". This is not how it works. Follow the steps below to run and publish Windows services.

Prerequisite note: If the target platform you set is x64, the directory you open will be different, otherwise the service will not run. You can right-click the project name, click [Properties] ->[Generate] ->[Target Platform] to view.

If it is not the x64 version, copy this address:

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

If it is the x64 version, copy this address:

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

Otherwise, an error similar to this will be reported:An exception occurred during initial installation: System.BadImageFormatException: Failed to load file or assembly...

(1) Then we add the above address (selected according to your own environment) to the environment variable. Click [Control Panel]——>[System and Security]

(2) Then click [System]

(3) Click [Advanced System Settings]

(4) Click [Environment Variables]

(5) Find Path in [System Variables], and then click [Edit].

(6) Then click [New], and then copy the directory we copied here. Then click Confirm.

(7) To test whether the configuration is successful, enter this command to check [InstallUtil]. If it looks like the following, it means it is successful.

(8) Then edit the solution and project.

(9) Run the cmd command as an administrator and then install the service.

InstallUtil project startup execution file full path

Example of Xigua programmer:

InstallUtil D:\Project demonstration temporary save\MyDemoService\MyDemoService\bin\Debug\MyDemoService.exe

(10) If this appears, the installation is successful.

(11) Open the service manager, find the service you want to start, and then right-click to start the service.

(12) If you want to uninstall the service, you can run this command:

InstallUtil /u Full path to project startup executable file

Example of Xigua programmer:

InstallUtil /u D:\Project demonstration temporary save\MyDemoService\MyDemoService\bin\Debug\MyDemoService.exe

5.3-Common commands

1. Installation service: Full path of the InstallUtil project startup execution file

2. Start the service: net start service name

3. Stop the service: net stop service name

4. Uninstall the service: InstallUtil /u The full path of the project startup execution file

5.4-Test consuming messages

(1) First, you can look at the log to see if the consumer service has been started successfully.

(2) Then record the consumption in the log, and query the [Message Track] of this message in the Alibaba Cloud background based on the message Key or message ID. If it prompts that the consumption is successful, it means that the consumption has indeed been carried out.

Finally, there may be scenarios such as message production failure and message consumption failure. The bosses can design and jump based on the actual situation.

6. Guide to preventing pitfalls

5.1: Type initializer for ons.ONSClient4CPPPINVOKE throws exception

Exception details:

Type initializer for 'ons.ONSClient4CPPPINVOKE' threw an exception.

solution:

Step 1: When using Visual Studio (VS) to develop .NET applications and class libraries, the default target platform is "Any CPU". However, the .NET SDK only supports Windows 64-bit operating system, so you need to set it up yourself. First right-click the [RocketMQ.Producer] project, then click [Properties], click [Generate] on the left option, and then change the target platform to [x64].

Step 2: Copy all the files in the resource package [ONSClient4CPP] folder to the [bin] directory.

5.2:Topic Route does not exist

Exception details:

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.”

Abnormal screenshot:

solution:

This problem is usually caused by the lack of connection to RocketMQ. Check whether the information in the configuration file is consistent with the RocketMQ information. Especially the access point information obtained by [ons_name_srv] RocketMQ version console is similar to "rmq-cn-XXXX.rmq.aliyuncs.com:8080". Remember not to add "http:// or https://". I often encounter this problem here, because only [VPC private network] access is set up, which means that RocketMQ cannot be accessed locally and can only be accessed on the server intranet.

5.3: Official documents are for reference only

Let’s complain about the official documentation of Cloud Message Queue RocketMQ (Alibaba Cloud Edition). It seems that it is not very friendly to .NET development students and only refers to the old version. When I was reading a lot of documents for development, I sometimes found that the downloaded case code was inconsistent with the code written online in the document. Then the document shows .NET SDK sample code, but what appears is other C++ language code.

I am a Xigua programmer, thank you all for reading and supporting me. It is not easy to write. If it is helpful to everyone, please use your little fortune to like and follow. Thank you very much! If you have any questions, please contact me to learn and discuss together~

Open source address:

Gitee:​​https://gitee.com/kimiliucn/Kimi.RocketMQ.NET​

GitHub:​​https://github.com/kimiliucn/Kimi.RocketMQ.NET​

Previous chapter:Practical use of RocketMQ (Alibaba Cloud version) in .NET Framework [Chapter 1]_Xigua Programmer’s Blog-CSDN Blog

 

Copyright statement: This article is an original article, and the copyright belongs to [Xigua Programmer]. Please indicate the source when reprinting. If you have any questions, please send a private message.

Original link:Practical use of RocketMQ (Alibaba Cloud version) in .NET Framework [Chapter 2]_Xigua Programmer’s Blog-CSDN Blog

Guess you like

Origin blog.csdn.net/2301_79251107/article/details/132581955