Tragedy of third-party components referencing another third-party component

Source: Internet
Author: User
Tags log4net

First, I declare that my summary was intentionally written in this way. If you read the summary, please make me laugh three times: Hahaha ~~

However, since you have already come in, you may wish to continue looking at it ~~

Event background

I have recently switched jobs and encountered a tricky problem in the project I just took over. A third-party component uses the old version of log4net (1.2.10 ), the new version of log4net (1.2.13) is used in another third-party component)

This is a problem.

When the two third-party components need to be used in my own project at the same time, the log4net versions referenced by them are inconsistent.

Therefore, no matter which version of log4net I reference, the final effect is that an exception will be thrown when another component is initialized.

For example:

Because both of them are non-open-source projects, they cannot be re-compiled. Fortunately, one of the components has technical support, so they contacted their service staff.

After some negotiations, the problem was initially solved.

The service is still very good !! Like one !!!!

But from the last sentence, we can see that the final reason is still in design !!

Why must log4net be coupled?

Yes ~ I admit that log4net is indeed a good log component, but even a good one is not necessary and indispensable!

Think about JQuery, a good js component, there are still many companies that do not use jquery. jquery is often called jquery plug-in because once jquery becomes invalid (or not referenced ), your components cannot be used.

Therefore, when developing your own components, You need to locate them clearly!

Is this log4net plug-in or is it functionally independent ??? Is the component unable to work without log4net ??

Even if it is more powerful, it is also a helper, and it is not indispensable!

Log Design of third-party components

Assuming that there is a third-party component, it is not difficult to use it.

Static void Main (string [] args) {// initialize a third-party control (read configuration files and other operations) SendMessage sm = new SendMessage (); // set the parameter sm. arg1 = "1"; sm. arg2 = "2"; sm. arg3 = "3"; sm. arg4 = "4"; // execution method, returns var result = sm. send (); Console. writeLine (result );}

However, if SendMessage is written in this way

Public class SendMessage {ILog Log; public SendMessage () {Log = log4net. logManager. getLogger (typeof (SendMessage); Log. info ("initialization completed");} public string Arg1 {get; set;} public string Arg2 {get; set;} public string Arg3 {get; set ;} public string Arg4 {get; set;} public string Send () {try {Log. info ("Send request"); Log. infoFormat ("parameter 1 = {0}; 2 = {1}; 3 = {2}; 4 = {3};", Arg1, Arg2, Arg3, Arg4 ); string result = null ;//..... log. info ("return Value:" + result); return result;} catch (Exception ex) {Log. error ("exception", ex); throw ;}}}

There may be situations I mentioned in section 1.

In addition, this SendMessage is highly coupled with log4net!

Change your own interface

This is the easiest way to implement

Let's discard log4net first ~ Then declare an ILog Interface

public interface ILog{    void Info(string message);    void Debug(string message);    void Warn(string message);    void Error(string caption, Exception ex);}

Then replace it with SendMessage.

Public class SendMessage {ILog Log log; public SendMessage (ILog Log) {log = log; if (Log! = Null) {Log. info ("initialization completed") ;}} public SendMessage () {} public string Arg1 {get; set;} public string Arg2 {get; set ;} public string Arg3 {get; set;} public string Arg4 {get; set;} public string Send () {try {if (Log! = Null) {Log. info ("Send request"); Log. info (string. format ("parameter 1 = {0}; 2 = {1}; 3 = {2}; 4 = {3};", Arg1, Arg2, Arg3, arg4);} string result = null ;//..... if (Log! = Null) {Log. Info ("returned value is:" + result);} return result;} catch (Exception ex) {if (Log! = Null) {Log. Error ("exception", ex) ;}throw ;}}}

In this way, the operation right of the log is handed over, so that the caller can consider how to complete the operation.

 

Well, I just want to debug it, and I don't want to persist the log information, so I can do this.

Static void Main (string [] args) {// initialize a third-party control (read configuration files and other operations) SendMessage sm = new SendMessage (new MyLog (); // set the parameter sm. arg1 = "1"; sm. arg2 = "2"; sm. arg3 = "3"; sm. arg4 = "4"; // execution method, returns var result = sm. send (); Console. writeLine (result);} class MyLog: ILog {public void Info (string message) {Console. writeLine ("info:" + message);} public void Debug (string message) {Console. writeLine ("debug:" + message);} public void Warn (string message) {Console. writeLine ("warn:" + message);} public void Error (string caption, Exception ex) {Console. writeLine ("error:" + caption); Console. writeLine ("error:" + ex. toString ());}}

If you want to continue using log4net

class MyLog : ILog{    log4net.ILog Log;    public MyLog()    {        Log = log4net.LogManager.GetLogger(typeof(MyLog));    }    public void Info(string message)    {        Log.Info(message);    }    public void Debug(string message)    {        Log.Debug(message);    }    public void Warn(string message)    {        Log.Warn(message);    }    public void Error(string caption, Exception ex)    {        Log.WriteLine(caption, ex);    }}

In fact, this is a good time to decouple log4net !!

 

If you do not want to understand the Trace and Debug classes of the system, you can directly jumpConclusionNow

Use System Objects (interfaces/abstract classes)

Speaking of this, I am a very lazy person who can define less classes and define less classes as much as possible.

So I don't need to define the ILog interface, because the system has already provided the corresponding object TraceListener for us.

So I did this directly!

Public class SendMessage {TraceListener Log; public SendMessage (TraceListener log) {Log = log; if (log! = Null) {Log. write ("initialization completed");} public SendMessage () {} public string Arg1 {get; set;} public string Arg2 {get; set;} public string Arg3 {get; set;} public string Arg4 {get; set;} public string Send () {try {if (Log! = Null) {Log. write ("Send request"); Log. write (string. format ("parameter 1 = {0}; 2 = {1}; 3 = {2}; 4 = {3};", Arg1, Arg2, Arg3, arg4);} string result = null ;//..... if (Log! = Null) {Log. Write ("returned value is:" + result);} return result;} catch (Exception ex) {if (Log! = Null) {Log. Write (ex, "exception") ;}throw ;}}}

Now I have killed the ILog interface.

Therefore, when using components, You Need To Inherit TraceListener.

Class MyLog: TraceListener {// public override void Write (string message) {this. writeLine ("info:" + message);} // public override void WriteLine (string message) {Console. writeLine (message) ;}// rewrite allowed. Do not Write public override void Write (object o, string category) {if (o is Exception) {Console. writeLine ("error:" + category); Console. writeLine ("error:" + o. toString ();} else {this. writeLine (category + ":" + o. toString ());}}}

Only void Write (string message) and void WriteLine (string message) are required.

You can choose to rewrite other data.

For example, if you do not overwrite Write (object o, string category), The Write (string message) method is called.

Encapsulation Method

A lot

if (Log != null){    Log.Write(message);}

In addition, this is only a demo project. There will be more such items in the real project, so the method must be encapsulated.

Public string Send () {try {Info ("Send request"); Info (string. format ("parameter 1 = {0}; 2 = {1}; 3 = {2}; 4 = {3};", Arg1, Arg2, Arg3, Arg4 )); string result = null ;//..... info ("return Value:" + result); return result;} catch (Exception ex) {Error ("Exception", ex); throw ;}} private void Info (string message) {if (Log! = Null) {Log. Write (message) ;}} private void Error (string caption, Exception ex) {if (Log! = Null) {Log. Write (ex, caption );}}
How to use the system

As I said before, I am a very lazy person. If I can write less than one method, I need to write less than one method.

Therefore, I don't actually need to encapsulate the method. I just need to use the system method directly, and even the constructor saves me!

Public class SendMessage {public SendMessage () {Trace. writeLine ("initialization completed");} public string Arg1 {get; set;} public string Arg2 {get; set;} public string Arg3 {get; set ;} public string Arg4 {get; set;} public string Send () {try {Trace. writeLine ("Send request"); Trace. writeLine (string. format ("parameter 1 = {0}; 2 = {1}; 3 = {2}; 4 = {3};", Arg1, Arg2, Arg3, Arg4 )); string result = null ;//..... trace. writeLine ("return Value:" + result); return result;} catch (Exception ex) {// all three methods are supported, but only WriteLine can accept the object parameters, this is a comparison of 2 // Trace. traceError ("exception:" + ex. toString (); // Trace. fail ("exception:" + ex. message, ex. stackTrace); Trace. writeLine (ex, "exception:"); throw ;}}}

Since the constructor has been changed, you also need to modify it when using it.

 

Static void Main (string [] args) {// sets the output log component Trace. listeners. add (new MyLog (); // initialize a third-party control (read configuration files and other operations) SendMessage sm = new SendMessage (); // set the parameter sm. arg1 = "1"; sm. arg2 = "2"; sm. arg3 = "3"; sm. arg4 = "4"; // execution method, returns var result = sm. send (); Console. writeLine (result );}
Class MyLog: TraceListener {// public override void Write (string message) {this. writeLine ("info:" + message);} // public override void WriteLine (string message) {Console. writeLine (message) ;}// rewrite allowed. Do not Write public override void Write (object o, string category) {if (o is Exception) {Console. writeLine ("error:" + category); Console. writeLine ("error:" + o. toString ();} else {this. writeLine (category + ":" + o. toString ());}}}MyLog remains unchanged

Effect

 

For details about Trace, refer to the Article (using C # built-in component strong program log)

Conclusion

What I want to express in this article is:Third-party components should not be coupled with other third-party components unless necessary

This is like kidnapping a user: If you use my components, you must use xxx. Otherwise, my components cannot be used.

Unless you are working on components in the form of "plug-ins", why are all my components open-source? I hope you can directly package the source code in the program when using them, instead of referencing dll, this will bring troubles to your users.

The second point of this article is to name the previous article (using C #'s built-in component strong program log, how many people understand Microsoft's Trace module as an interface, not a log component

Finally, I want to say that I didn't say that log4net is not good, and I didn't want everyone to use log4net, but when we were using log4net (and third-party components of other auxiliary classes ),

Decouple it as much as possible and do not rely too much (direct reference)

Prevents a secondary function from being invalid (or incorrect) and causes the entire system to crash.

 

When referencing a third-party component, you should also pay attention to making it referenced in a project as much as possible, and then use the object or interface for secondary encapsulation.

Avoid a reference relationship between a component in all projects. In the same way, a function described above becomes invalid (or incorrect) and the entire system crashes.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.