Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Support Syndication Support Rss Optional Elements#25625

Closed
shmao wants to merge 9 commits intodotnet:masterfrom
shmao:OptionalElements
Closed

Support Syndication Support Rss Optional Elements#25625
shmao wants to merge 9 commits intodotnet:masterfrom
shmao:OptionalElements

Conversation

@shmao
Copy link
Contributor

@shmao shmao commented Dec 1, 2017

I'm prototyping supporting RSS optional elements using the <docs>element. Please let me know if you have any concerns or suggestions. I'll apply this to other optional elements after this PR.

The change enable users to read/wring <docs> via SyndicationFeed.Documentation . Here's a couple of things worth to note:

  1. Any existing applications that read/write <docs> via SyndicationFeed.ElementExtensions would still work after the change.
  2. If SyndicationFeed.Documentation is ever used and becomes not null, SyndicationFeedFormatter.WriteTo would write <docs> with the value of SyndicationFeed.Documentation and ignore the corresponding ElementExtension.

Ref #25608.

@shmao shmao self-assigned this Dec 1, 2017
@shmao shmao requested review from mconnew and zhenlan December 1, 2017 01:52
@shmao shmao added this to the 2.1.0 milestone Dec 1, 2017
using (XmlReader reader = documentationElement.GetReader())
{
SyndicationLink documentation = new Rss20FeedFormatter().ReadAlternateLink(reader, BaseUri);
return documentation;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReadAlternateLink uses a UriParser which is why you need to instantiate an instance of Rss20FeedFormatter. This is just going to use the default Uri parser so we lose the benefit of the extensibility here. We should make ReadAlternateLink be a static method which takes a Uri parser as a parameter . Then do one of two things. 1) Have the class which instantiates the SyndicationFeed class set the parser in SyndicationFeed so any custom parser can be passed to ReadAlternateLink. 2) Pass the default Uri parser to ReadAlternateLink as that's what's being used here anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I went with option 2).

xmlw.Close();
using (XmlWriter xmlw = XmlWriter.Create(path))
{
Rss20FeedFormatter atomFeed = new Rss20FeedFormatter(sf);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems oddly written. An instance of Rss20FeedFormatter is called atomFeed when we have an atom formatter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. The naming error was there before I changed this. Here I'm fixing the usage of the Close() method which was not called when exception happened in WriteTo.

I'll fix the names.

Rss20FeedFormatter atomFeed = new Rss20FeedFormatter(sf);
atomFeed.WriteTo(xmlw);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no verification that we round trip all data?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I noticed this problem. But this is not a new added test. I'm fixing the usage of Close here.

<!--
<image>
<url>http://2.bp.blogspot.com/-NA5Jb-64eUg/URx8CSdcj_I/AAAAAAAAAUo/eCx0irI0rq0/s1600/bg_Contoso_logo3-20120824073001907469-620x349.jpg</url>
<title>The title is not the same to the original one</title>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is commented out XML but this is a very real URL to a real image. Do we want to remove this or sanitize the values?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a bug with the original implementation of reading <image>, which read different values and failed the tests. I'm commenting out this section out for now. We will need to revisit this when we add support for <image>.

public partial class SyndicationFeed
{
public SyndicationLink Documentation { get{ throw null; } set{ } }
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has this been through API review? If not, we should close the PR until it's been vetted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has not been approved yet. I added the NO MERGE label on the PR for now. I'd like to get feedback from others and see if it's even possible or make sense to add the new APIs before sending out API request..

@shmao shmao added the * NO MERGE * The PR is not ready for merge yet (see discussion for detailed reasons) label Dec 5, 2017
if (Feed.GetDocumentation() != null)
{
writer.WriteElementString(Rss20Constants.DocumentationTag, Feed.GetDocumentation().Uri.ToString());
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uri can be null

}

internal SyndicationLink GetDocumentation()
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically a property getter. Can you change this to a read only property with a name such as InternalDocumentation.

@mconnew
Copy link
Member

mconnew commented Dec 7, 2017

Just the one small issue (method -> property), otherwise LGTM.

// NOTE: This class implements Clone so if you add any members, please update the copy ctor
public class SyndicationFeed : IExtensibleSyndicationObject
{
private readonly static List<string> s_acceptedDays = new List<string> { "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday" };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: static readonly (static before readonly)

set { _title = value; }
}

internal SyndicationLink InternalDocumentation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Could be simplified as:

internal SyndicationLink InternalDocumentation => _documentation;

}
}

internal int? InternalTimeToLive
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Could be simplified as:

internal int? InternalTimeToLive => _timeToLive;

}
}

internal Collection<int> InternalSkipHours
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Could be simplified as:

internal int? InternalTimeToLive => _skipHours;

}
}

internal Collection<string> InternalSkipDays
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Could be simplified as:

internal int? InternalTimeToLive => _skipDays;


if (hour < 0 || hour > 23)
{
throw new ArgumentException("The hour can't be lower than 0 or greater than 23.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String should be added to the resources.

return isValidTextInput(textInput) ? textInput : null;
}

private bool isValidTextInput(SyndicationTextInput textInput)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isValidTextInput => IsValidTextInput and can be static.

case Rss20Constants.DocumentationTag:
if (InternalDocumentation != null)
{
return true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These can be simplified, e.g.:

switch (localName)
{
    case Rss20Constants.DocumentationTag:
        return InternalDocumentation != null;

    case Rss20Constants.TimeToLiveTag:
        return InternalTimeToLive != null;

    case Rss20Constants.TextInputTag:
        return  InternalTextInput != null;

    // etc.
}


break;

default:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default case isn't necessary

private SyndicationLink TryReadDocumentationFromExtension(SyndicationElementExtensionCollection elementExtensions)
{
SyndicationElementExtension documentationElement = elementExtensions
.Where((e) => e.OuterName == Rss20Constants.DocumentationTag && e.OuterNamespace == Rss20Constants.Rss20Namespace)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: (e) => ... can be simply e => .... Applies throughout.

_timeToLive = TryReadTimeToLiveFromExtension(ElementExtensions);
}

return _timeToLive.Value;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is InvalidOperationException if TryReadTimeToLiveFromExtension returns null appropriate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I changed the type of the property to int?. Thanks.

@shmao shmao changed the title Syndication Support Documentation Element. Support Syndication Support Rss Optional Elements Dec 12, 2017
@shmao
Copy link
Contributor Author

shmao commented Dec 12, 2017

@justinvp @JonHanna Thanks for reviewing the PR. I've made changes per your suggestions.

@shmao
Copy link
Contributor Author

shmao commented Dec 13, 2017

The proposed APIs have not been reviewed yet. See https://github.com/dotnet/corefx/issues/25718.

I will be out of office and be back on Jan 2, 2018. I'm leaving the PR open for now. If the the APIs are approved, please feel free to merge the PR. If anyone feels the PR being open for too long, please feel free to close it. Thanks.

@shmao
Copy link
Contributor Author

shmao commented Jan 9, 2018

@dotnet-bot test OSX x64 Debug Build

@karelz karelz added the blocked Issue/PR is blocked on something - see comments label Jan 18, 2018
@huanwu huanwu assigned mconnew and unassigned huanwu, zhenlan and shmao Jan 18, 2018
@karelz
Copy link
Member

karelz commented Jan 27, 2018

Closing, it's replaced by PR #26612

@karelz karelz closed this Jan 27, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.ServiceModel.Syndication blocked Issue/PR is blocked on something - see comments * NO MERGE * The PR is not ready for merge yet (see discussion for detailed reasons)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants