MailMessage"从"财产转让间接导致的异常 [英] MailMessage "From" property assignment indirectly causes exception

查看:128
本文介绍了MailMessage"从"财产转让间接导致的异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我在计算器的第一个问题!

This is my first question on StackOverflow!

不过,我解决了这个问题(意外),但并不真正了解的奇怪的行为。

However, I solved the problem (by accident), but don't really understand the strange behavior.

下面code类火灾的异常:

The following code fires an exception:

...
MailMessage ms = new MailMessage();
MailAddress from = new MailAddress("my@email.address", "my display name (in hebrew)");
ms.From = from;
...

我得到的例外是:

The exception I get is:

"Failure sending mail."
(The inner exception message is: "An invalid character was found in header value.")

不过,如果我直接分配新的实例从属性(你可以在下面的code片段见),一切工作正常。

However, If I assign the new instance directly to the "From" property (as you can see in the following code fragment), everything works as expected.

...
MailMessage ms = new MailMessage();
ms.From = new MailAddress("my@email.address", "my display name (in hebrew)");
...

没有任何一个有什么想法?

Does any one have any idea?

感谢: - )

修改1:重现步骤

由于@ShadowWizard表明,这是很难用一个干净的控制台应用程序来重现此问题。因此,我会尽力调查什么在我的应用程序,导致这种奇怪的行为怎么回事。

As @ShadowWizard suggests, it is hard to reproduce this problem using a clean console application. Hence I will try to investigate what is going on in my application that causes this strange behavior.

推荐答案

OK,

现在我知道如何重现此问题以及如何解决它(或以上excatly如何避免它)。

Now I know how to reproduce this issue as well as how to solve it (or more excatly how to avoid it).

要复制,创建一个空的.NET 3.5的控制台应用程序,并复制下面的code。

To reproduce, create an empty .NET 3.5 console application and copy the following code.

namespace Example
{
    class Program
    {
        private static SmtpClient _smtp = null;
        public static SmtpClient Smtp
        {
            get
            {
                if (_smtp == null)
                {
                    _smtp = new SmtpClient("relay.your-smtp-host.com", 25);
                    _smtp.UseDefaultCredentials = true;
                }
                return _smtp;
            }
        }

        static void Main(string[] args)
        {
            using (MailMessage ms = new MailMessage())
            {
                var from = new MailAddress("from@email-address.com", "**THE NAME MUST CONTAINS SOME NON ANSI CHARS**");

                string s = from.ToString(); /* This is the line - comment it and everything will work fine! */

                ms.From = from;
                ms.To.Add(new MailAddress("recipient@address.co.il"));
                ms.Subject = "Here is my message title";
                ms.Body = "Here is my message body";
                Smtp.Send(ms);
            }
        }
    }
}

注意:

  1. 要重现该问题,您必须将显示名称属性中一些非ANSI字符。
  2. 运行此程​​序一次不带破发点,然后注释行字符串s = from.ToString(),然后再运行。
  1. To reproduce the issue, you must put some NON ANSI characters within the DisplayName property.
  2. Run this program once without break points, then comment the line string s = from.ToString() and run again.

正如你可以看到,如果的ToString方法之前调用Smtp.Send调用,将引发异常。

As you can see, if the "ToString" method is called prior to the call to Smtp.Send, an exception is thrown.

好吧,我碰到了摆在首位这个问题,因为我跑与破发点中的应用,所以调试器调用幕后的ToString()方法。

(为了让事情更清晰,简单地说行:

(To make things more clear, simply put the line:

System.Diagnostics.Debug.WriteLine(from)

在调用Smtp.Send,则调用后移动)。

before the call to Smtp.Send, then move it after the call).

问:

,这是什么奇怪的行为的原因是什么?

What is the reason for this strange behavior?

答:

时散发出来的在 .NET Framework 3.5的有内MailAddress类两种方法设置一个名为fullAddress两种不同的方式内场。

Is comes out that within .NET framework 3.5 there are two methods within MailAddress class that set an internal field named "fullAddress" in two different ways.

第一种方法是TOEN codedString():

The first method is ToEncodedString():

internal string ToEncodedString()
{
    if (this.fullAddress == null)
    {
        if ((this.encodedDisplayName != null) && (this.encodedDisplayName != string.Empty))
        {
            StringBuilder builder = new StringBuilder();
            MailBnfHelper.GetDotAtomOrQuotedString(this.encodedDisplayName, builder);
            builder.Append(" <");
            builder.Append(this.Address);
            builder.Append('>');
            this.fullAddress = builder.ToString();
        }
        else
        {
            this.fullAddress = this.Address;
        }
    }
    return this.fullAddress;
}

的第二种方法是的ToString():

The second method is ToString():

public override string ToString()
{
    if (this.fullAddress == null)
    {
        if ((this.encodedDisplayName != null) && (this.encodedDisplayName != string.Empty))
        {
            StringBuilder builder = new StringBuilder();
            if (this.DisplayName.StartsWith("\"") && this.DisplayName.EndsWith("\""))
            {
                builder.Append(this.DisplayName); 
            }
            else
            {
                builder.Append('"');
                builder.Append(this.DisplayName);
                builder.Append('"');
            }
            builder.Append(" <");
            builder.Append(this.Address);
            builder.Append('>');
            this.fullAddress = builder.ToString();
        }
        else
        {
            this.fullAddress = this.Address;
        }
    }
    return this.fullAddress;
}

现在,在SmtpClient,发送消息时,它触发的设置从头:

Now, within SmtpClient, when sending the message, it triggers the settings of "From" header:

this.Headers[MailHeaderInfo.GetString(MailHeaderID.From)] = this.From.ToEncodedString();

这反过来触发以下方法:

which in turn triggers the following method:

public override void Set(string name, string value)
{
    if (Logging.On)
    {
        Logging.PrintInfo(Logging.Web, this, "Set", name.ToString() + "=" + value.ToString());
    }
    if (name == null)
    {
        throw new ArgumentNullException("name");
    }
    if (value == null)
    {
        throw new ArgumentNullException("value");
    }
    if (name == string.Empty)
    {
        throw new ArgumentException(SR.GetString("net_emptystringcall", new object[] { "name" }), "name");
    }
    if (value == string.Empty)
    {
        throw new ArgumentException(SR.GetString("net_emptystringcall", new object[] { "value" }), "name");
    }
    if (!MimeBasePart.IsAscii(name, false))
    {
        throw new FormatException(SR.GetString("InvalidHeaderName"));
    }
    if (!MimeBasePart.IsAnsi(value, false))
    {
        throw new FormatException(SR.GetString("InvalidHeaderValue"));
    }
    name = MailHeaderInfo.NormalizeCase(name);
    MailHeaderID iD = MailHeaderInfo.GetID(name);
    if ((iD == MailHeaderID.ContentType) && (this.part != null))
    {
        this.part.ContentType.Set(value.ToLower(CultureInfo.InvariantCulture), this);
    }
    else if ((iD == MailHeaderID.ContentDisposition) && (this.part is MimePart))
    {
        ((MimePart) this.part).ContentDisposition.Set(value.ToLower(CultureInfo.InvariantCulture), this);
    }
    else
    {
        base.Set(name, value);
    }
}

该方法将验证标头值包含通过网络发送(因为SMTP协议限制)之前,仅ANSI字符。但fullAddress现场已经被设置与非ANSI字符通过调用toString()方法。因此,发送了失败,原因是例外,说有无效字的头。

This method validates that the header value contains only ANSI character before sending it through the network (because of SMTP protocol limitations). But the "fullAddress" field was already set with non ANSI characters by a call to ToString(). Hence the sending was failed due to exception, saying that there are "Invalid" characters in the header.

在寻找在.NET 4.0中体现code看来,这个问题是解决了完全重写MailAddress的内部实现!

After looking in the reflected code of .NET 4.0 it seems that this issue was solved by totally rewriting the internal implementation of MailAddress!

感谢您想帮助!

P.S。 @ShadowWizard正如你所看到的,有时候有什么: - )

P.S. @ShadowWizard As you can see, sometimes there is nothing :-)

这篇关于MailMessage&QUOT;从&QUOT;财产转让间接导致的异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆