Ivan Stoyanov
Ivan Stoyanov

Reputation: 5482

Problem with Substring() - ArgumentOutOfRangeException

I have a repeater that displays data from my Projects table. There are projectId, name and description. I use Substring(1, 240) on description. But sometimes the string is shorter than 240, so I get ArgumentOutOfRangeException. Can you tell me how to display the whole text if I get the exception. This is my code.

    <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<asp:Panel ID="pnlDisplayProjects" runat="server" Visible="true">
    <center><h2><b>Проекти</b></h2></center>
        <asp:Repeater ID="rptrProjects" runat="server">
            <HeaderTemplate>
                <table border="1" cellpadding="2" cellspacing="2" align="center" width="80%" style="background-color:#F7F6F3;">
            </HeaderTemplate>
            <ItemTemplate>
                <tr>
                    <td align="left" style="width:40px">
                        <asp:Label ID="LblProjectId" runat="server" Text='<%# Eval("ProjectID") %>' />
                    </td>
                    <td align="center">
                        <asp:Label ID="LblName" runat="server" Text='<%# Eval("Name") %>' />
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        <asp:Label ID="LblDescription" runat="server" Text='<%# Eval("Description").ToString().Substring(1, 240) + "..." %>'/>
                        <asp:HyperLink ID="HlMore" runat="server" NavigateUrl='<%#"~/Project/ViewProject.aspx?projectId=" + Eval("ProjectID") %>' Text="More" />
                    </td>
                </tr>
            </ItemTemplate>
            <FooterTemplate>
                </table>
            </FooterTemplate>
        </asp:Repeater>
</asp:Panel>

 protected override void OnPreRender(EventArgs e)
    {
        var table = Projects.GetTableWithProjects();

        if (table.Rows.Count > 0)
        {
            rptrProjects.DataSource = table;
            rptrProjects.DataBind();
        }
        else
        {
            pnlDisplayProjects.Visible = false;
            Master.PrintMessage("There are no projects.");
        }
    }

Upvotes: 27

Views: 34987

Answers (12)

Cleber Spirlandeli
Cleber Spirlandeli

Reputation: 143

Using .Net 5 or higher.

I recommend using:

yourText.Substring(0, Math.Min(yourText.Length, 100));

This logic will use the smallest value between the comparisons, as it returns the smallest of two numbers. As per MS documentation.

Upvotes: 0

Ben Wilde
Ben Wilde

Reputation: 5672

Let's try to keep this simple...

We only need to truncate to a given max length, so how about we call it what it is:

description.TruncateTo(240);

The extension method that enables the above (ellipsis is appended by default if truncated):

public static class StringExtensions
{
    public static string TruncateTo(this string val, int maxLength, bool ellipsis = true)
    {
        if (val == null || val.Length <= maxLength)
        {
            return val;
        }

        ellipsis = ellipsis && maxLength >= 3;
        return ellipsis ? val.Substring(0, maxLength - 3) + "..." : val.Substring(0, maxLength);
    }
}

Upvotes: 0

description.Substring(0, Math.Min(description.Length, 240));

Upvotes: 21

IordanTanev
IordanTanev

Reputation: 6240

string dec = "description";
string result = dec.Substring( 0, dec.Length > 240 ? 240 : dec.Length )

Upvotes: 46

skini
skini

Reputation: 23

You can use LINQ as below:

string someString = "abcde"; 
string subStr = string.Join("", someString.Take(240));

Upvotes: 2

superlogical
superlogical

Reputation: 14950

Based on Jon Skeet's answer, I think it should be checking for null or else it's not exactly a safe method :)

public static string SafeSubstring(this string text, int start, int length)
{
    if (text == null) return null;      

    return text.Length <= start ? ""
        : text.Length - start <= length ? text.Substring(start)
        : text.Substring(start, length);
}

Upvotes: 5

Nick
Nick

Reputation: 5955

Text='<%# Eval("Description").ToString().Substring(1, Math.Min(240, Eval("Description").ToString().Length - 1)) + "..." %>'

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1502306

I would suggest you write a separate extension method if you're using .NET 3.5. Something like this:

public static string SafeSubstring(this string text, int start, int length)
{
    return text.Length <= start ? ""
        : text.Length - start <= length ? text.Substring(start)
        : text.Substring(start, length);
}

Basically that's a version of Substring which will never throw an exception unless start or length is negative (in which case I don't know what it could sensibly return).

You'd call it like this:

Eval("Description").ToString().SafeSubstring(1, 240) + "..."

The downside of this is that it will include the ellipsis (...) even if it's not actually truncated the string at all...

Upvotes: 52

Phil Haselden
Phil Haselden

Reputation: 3016

An extension method:

public static string SafeSubstring(this string text, int start, int length)
{
   if (start >= text.Length)
      return "";            
   if (start + length > text.Length)
      length = text.Length - start;         
   return text.Substring(start, length);
}

Upvotes: 3

ewrankin
ewrankin

Reputation: 263

Another option is to write a a method that you call so your eval turns into:

<%# GetString(Container.DataItem) %>

So in the method you could check to make sure that the item is NOT null because you may bomb out calling .ToString on a NULL item. Then you can evaluate the container item and pass in the length to the substring call.

Upvotes: 0

Nathan Wheeler
Nathan Wheeler

Reputation: 5932

If you REQUIRE 240 characters in that place for some reason, you can cast that field coming out of the database as a char(241) in which case it will always be 241 characters, with padding to the right if the content of the field was shorter than 241 characters. Then you can still strip off the first character with the Substring(1, 240) as you are right now.

Although, I must wonder if you're not wanting to do a Substring(0, 240) which wouldn't throw an exception if the string was shorter than 240 characters, and would start at the beginning of the string, rather than the 2nd character.

Upvotes: 0

David
David

Reputation: 73584

It's a bit of a hack, but the simplest method would be to change:

Eval("Description").ToString().Substring(1,240)

to

Eval("Description").ToString().PadRight(240).Substring(1, 240)

I'm not sure about the performance considerations on this, though, if therre are a lot of items.

Upvotes: 1

Related Questions