ajax paging asp.net mvc - asp.net

I know how to hook up ajax paging to a grid or a webgrid in asp.net mvc. But how can I accomplish ajax paging, using custom paging for large data sets for another format outside of a table grid.
Is that even possible using an mvc helper or mvc.pagedlist?
I used to be a webforms guys and it was so easy to hook up a listview where you could use divs to create whatever layout you want for individual items, you could then hook up a datapage and wrap it all in an update panel.
Basically I want a list of items that I can page through via ajax but with having large data sets I can just pull down all the items and page via jquery, I need to do custom paging on the server side and only return the items for a specific page.

By reusing a partial view and some ajax, this is very easily done in MVC.
Add this model as a property to your page's ViewModel to handle the pagination:
namespace Models.ViewModels
{
[Serializable()]
public class PagingInfoViewModel
{
public int TotalItems { get; set; }
public int ResultsPerPage { get; set; }
public int CurrentPage { get; set; }
public int TotalPages {
get { return Convert.ToInt32(Math.Ceiling(Convert.ToDecimal(this.TotalItems) / this.ResultsPerPage)); }
}
public string LinkTextShowMore { get; set; }
public string LinkTextShowingAll { get; set; }
/// <summary>
/// Paging url used by the jQuery Ajax function
/// </summary>
public string UrlGetMore { get; set; }
public PagingInfoViewModel(string linkTextShowMore, string linkTextShowingAll, int resultsPerPage)
{
this.LinkTextShowMore = linkTextShowMore;
this.LinkTextShowingAll = linkTextShowingAll;
this.ResultsPerPage = resultsPerPage;
}
}
}
Add the following code to your partial view to handle the pagination:
//Start Pagination
//determine the value for the X for "Showing X of Y"
{
int currentTotal = 0;
if ((Model.PagingInfo.CurrentPage * Model.PagingInfo.ResultsPerPage) < Model.PagingInfo.TotalItems) {
//the current max item we are displaying is less than the total number of policies
//display the current max item index\
currentTotal = Model.PagingInfo.CurrentPage * Model.PagingInfo.ResultsPerPage;
} else {
//the current is greater than the total number of policies
//display the total number of policies
currentTotal = Model.PagingInfo.TotalItems;
}
if (Model.PagingInfo.TotalPages == 0 || Model.PagingInfo.CurrentPage == Model.PagingInfo.TotalPages)
{
#<li>
<h3>#Model.PagingInfo.LinkTextShowingAll</h3>
<p><strong>Showing #currentTotal Of #Model.PagingInfo.TotalItems</strong></p>
</li>
} else {
#<li id="GetMore">
<a href="#" id="lnkGetMore">
<h3>#Model.PagingInfo.LinkTextShowMore</h3>
<p><strong>Showing #(currentTotal) Of #Model.PagingInfo.TotalItems</strong></p>
</a>
</li>
#<script type="text/javascript" lang="javascript">
$('#lnkGetMore').click(function () {
$.ajax({
url: "#Model.PagingInfo.UrlGetMore",
success: function (data) {
$('#ProducerList li:last').remove();
$('#ProducerList').append(data);
$('#ProducerList').listview('refresh');
}
});
return false;
});
</script>
}
}
Now, the javascript at the end is specifically for a UI that uses ul's and li's, but can easily be customized for your needs.
The UrlGetMore property is set on the back end when the model is passed to the view. I am sure there is a more elegant way of doing this. Here is the code I used:
//build paging url used by the jQuery Ajax function
view.PagingInfo.UrlGetMore == Url.RouteUrl("RouteItemList", new { page = view.PagingInfo.CurrentPage + 1 })
And finally, here is the action that handles both the initial View and the subsequent Partial View (ajax call)
public ActionResult List(UserModel user, ViewModel view, int page = 1)
{
IQueryable<model> models = this.RetrieveModels(user, view);
if ((models != null) && models.Count > 0) {
view.PagingInfo.CurrentPage = page;
view.PagingInfo.ResultsPerPage = user.Preferences.ResultsPerPage;
view.PagingInfo.TotalItems = models.Count;
view.items = models.Skip((page - 1) * user.Preferences.ResultsPerPage).Take(user.Preferences.ResultsPerPage).ToList();
//build paging url used by the jQuery Ajax function
view.PagingInfo.UrlGetMore = Url.RouteUrl("RouteList", new { page = view.PagingInfo.CurrentPage + 1 });
}
if (page == 1) {
return View(view);
} else {
return PartialView("ListPartial", view);
}
}
HTH.

You could create simple HtmlHelper simillar to this:
public static class HtmlPaginHelper
{
public static MvcHtmlString PagerNoLastPage(this AjaxHelper ajaxHelper,
int page,
int pageSize,
bool isLastPage,
Func<int, string> pageUrl,
Func<int, AjaxOptions> pageAjaxOptions)
{
var result = new StringBuilder();
var firstPageAnchor = new TagBuilder("a");
firstPageAnchor.SetInnerText("<<");
var prevPageAnchor = new TagBuilder("a");
prevPageAnchor.SetInnerText("<");
var nextPageAnchor = new TagBuilder("a");
nextPageAnchor.SetInnerText(">");
var currentPageText = new TagBuilder("span");
currentPageText.SetInnerText(string.Format("Page: {0}", page));
if (page > 1)
{
firstPageAnchor.MergeAttribute("href", pageUrl(1));
firstPageAnchor.MergeAttributes(pageAjaxOptions(1).ToUnobtrusiveHtmlAttributes());
prevPageAnchor.MergeAttribute("href", pageUrl(page - 1));
prevPageAnchor.MergeAttributes(pageAjaxOptions(page - 1).ToUnobtrusiveHtmlAttributes());
}
if (!isLastPage)
{
nextPageAnchor.MergeAttribute("href", pageUrl(page + 1));
nextPageAnchor.MergeAttributes(pageAjaxOptions(page + 1).ToUnobtrusiveHtmlAttributes());
}
result.Append(firstPageAnchor);
result.Append(prevPageAnchor);
result.Append(currentPageText);
result.Append(nextPageAnchor);
return MvcHtmlString.Create(result.ToString());
}
}
... and then use it in your Razor view:
grid results go here...
#Ajax.PagerNoLastPage(Model.Query.Page,
Model.Query.PageSize,
Model.Data.IsLastPage,
i => Url.Action("Index", RouteValues(i)),
i => new AjaxOptions
{
UpdateTargetId = "content",
InsertionMode = InsertionMode.Replace,
HttpMethod = "GET",
Url = Url.Action("Grid", RouteValues(i))
})
where RouteValues(i) is defined for example like this:
#functions {
private object PageRouteValues(int i)
{
return new
{
payId = Model.Query.PayId,
clientCode = Model.Query.ClientCode,
fromDate = Model.Query.FromDate,
tillDate = Model.Query.TillDate,
payNum = Model.Query.PayId,
checkNum = Model.Query.CheckNum,
payType = Model.Query.PayType,
payStatus = Model.Query.PayStatus,
page = i,
pageSize = Model.Query.PageSize
};
}
}

Is that even possible using an mvc helper or mvc.pagedlist?
Yes, but of course you have to coordinate the client-side requests with server-side actions to handle the actual data paging. In that sense, it's not as simple as as WebForms, but it's still possible.
Here's an example of using PagedList to render each returned item in its own table, separated by horizontal rules. You should easily be able to modify the HTML in the example to produce any rendering you want.

Related

Dynamically assign value to a Property

I have hard time understanding assigning value to a property dynamically, means during run time so that i can retrieve/display value in a razor page. I have following programming logic to accomplish my task, however this (LmitedWords) property does not render or hold any value to be displayed. How do I assign a value to this property during run time.
public class Post
{
public string Content { get; set; }
[NotMapped]
public string LimitedWords { get; set; }
}
My controller code follow:-
public async Task<IActionResult> GetAllPosts()
{
var myLimitProperty = new Post();
var result = await _repository.GetAllPosts();
foreach (var post in result)
{
var limitContent = ContentExtension.ReturnLimitedDescription(post.Content, size);
myLimitProperty.LimitedWords = limitContent;
}
return View(result);
}
my contentextension helper method returns value as expected and during debug it does show that local variable "limitContent" has the value but it somehow does not assign it to LimitedWords property, which is a property in Post class.
In my Post class there are other properties as well and i want them to be displayed as it is saved in the database.
My Razor page does not display content as it is null:
<div>
<markdown markdown="#Model.LimitedWords">
</div>
Thanks!
Well based on what you have posted, the result holds the posts returned by the repository.
You loop through these posts, update the myLimitProperty local variable in the action and return the original collection.
Nothing is actually being updated on objects being sent to the view
Create a projection from the list, populating the desired properties that should be displayed in the view.
public async Task<IActionResult> GetAllPosts() {
var posts = await _repository.GetAllPosts();
var result = posts.Select(post => {
var limitContent = ContentExtension.ReturnLimitedDescription(post.Content, size);
var model = new Post() {
Content = post.Content;
LimitedWords = limitContent;
};
return model;
}).ToList();
return View(result);
}

How to unit test the controller?

I have the controller in ASP.NET Mvc 6.
public class VendorManagementController : Controller
{
private readonly IVendorRespository _vendorRespository;
public VendorManagementController(IVendorRespository vendorRespository)
{
_vendorRespository = vendorRespository;
}
[Microsoft.AspNet.Mvc.HttpGet]
public dynamic GetVendorById(int pkey)
{
Vendor vendor = _vendorRespository.GetVendor(pkey);
return vendor;
}
// GET
// USing JqGrid
[Microsoft.AspNet.Mvc.HttpGet]
public dynamic GetVendors(string sidx, string sortOrder, int page, int rows, int pkey)
{
var vendors = _vendorRespository.GetAllVendors().AsQueryable();
var pageIndex = Convert.ToInt32(page) - 1;
var pageSize = rows;
var totalRecords = vendors.Count();
var totalPages = (int)Math.Ceiling((float)totalRecords / (float)pageSize);
return something
}
// POST
[System.Web.Http.HttpPost]
public string PostVendor(Vendor item)
{
_vendorRespository.AddVendor(item);
}
The link provides an example to test the controller, but it uses HttpRequestMessage. It doesn't fit my case.
So if I want to test the return Vendors, how?
Say I have the method:
[Fact]
public void GetAllVendors_ShouldReturnAllVendors()
{
var testVendors = GetTestVendors();
var vendorRespository = new VendorRespository();
var controller = new VendorManagementController(vendorRespository);
}
The thing is
var vendors = _vendorRespository.GetAllVendors().AsQueryable();
from the databse, how to mock up it with my fake vendors?
EDIT:
The method returns dynamic type, I can't get the Count of the list.
Install a mocking framework such as Moq from nuget - https://www.nuget.org/packages/Moq/.
using Moq;
[Fact]
public void GetAllVendors_ShouldReturnAllVendors()
{
var testVendors = GetTestVendors();
var vendorRespository = new Mock<IVendorRepository>();
vendorRepository.Setup(m => m.GetAllVendors()).Returns(new List<Vendor> { new Vendor() }); // Guessing a bit on return types
var controller = new VendorManagementController(vendorRespository.Object);
var result = controller.GetVendors( ... )
// Assert you get 1 Vendor back, not sure what you're planning to return by "something". :-)
}
Other frameworks are available, NSubsititute, FakeItEasy

How to use parameters in Twitter Bootstrap loaded dynamically from the database

I have a website where I need multiple themes.
So www.mysite.com/Client1/ uses red buttons and www.mysite.com/Client2/ uses blue buttons.
The number of clients are dynamic stores in a DB, and the colors are also stored in the DB. Can be changed at anytime by the client.
Currently I am using Twitter Bootstrap LESS files and ASP MVC Optimization (bundle).
My App_Start BundleConfig looks like this:
var cssTransformer = new CssTransformer();
var stylesBundle = new StyleBundle("~/Content/bootstrap");
.Include("~/Content/less/bootstrap.less")
stylesBundle.Transforms.Add(cssTransformer);
bundles.Add(stylesBundle);
In variables.less
#btnPrimaryBackground: #linkColor;
The color of #btnPrimaryBackground should change when different urls are called.
How do I change the less variable to use a parameter from my another source (database or other)?
Since Web Optimization does not play nice with dynamic dontent, I decided to not use it.
Instead I have made am ASP MVC ActionResult for LESS, and reference that.
<link rel="stylesheet" type="text/css" href="#Url.Action("Styles", "Theme")">
My ASP MVC Controller looks like this:
public class ThemeController : Controller
{
public ActionResult Styles()
{
var parameters = new Dictionary<string, string>
{
{"themeColor1", "Get theme color 1 here"},
{"themeColor2", "Get theme color 2 here"}
};
var themeLessFilePath = Server.MapPath("~/Content/less/theme.less");
using (var stream = System.IO.File.OpenRead(themeLessFilePath))
{
return new DotLessResult(stream, parameters, true);
}
}
}
And the LESS ActionResult like this:
public class DotLessResult : ActionResult
{
public IDictionary<string, string> Parameters { get; set; }
public string Less { get; set; }
public bool Minify { get; set; }
public DotLessResult(string less, IDictionary<string, string> parameters = null, bool minify = false)
{
Less = less;
Parameters = parameters ?? new Dictionary<string, string>();
Minify = minify;
}
public DotLessResult(Stream stream, IDictionary<string, string> parameters = null, bool minify = false)
: this(new StreamReader(stream).ReadToEnd(), parameters, minify) { }
public override void ExecuteResult(ControllerContext context)
{
var output = Less;
//TODO: Not the way to do this!
foreach (var key in Parameters.Keys)
{
output = Regex.Replace(output, #"#" + key + #":\s*\S+;", "#" + key + ":" + Parameters[key] + ";");
}
var lessEngine = dotless.Core.LessWeb.GetEngine(new DotlessConfiguration { MinifyOutput = Minify, MapPathsToWeb = true, Web = true, CacheEnabled = false});
var css = lessEngine.TransformToCss(output, (string)null);
context.HttpContext.Response.ContentType = "text/css";
using (var writer = new StreamWriter(context.HttpContext.Response.OutputStream, Encoding.UTF8))
{
writer.Write(css);
writer.Flush();
}
}
}
Its NOT the best solution, but it works on my machine TM.
Dont forget to implement some kind of output caching as it will most like be hit alot, and not change very often.

Making TPL Async calls from mvc controller on click of submit button

Basically I want to implement simple search functionality, whenever user enters some keyword in the text box on view and clicks submit button I want to make ASYNC calls to predefined website urls using TPL Async mechanism. When I do the same with console application it works like a charm but not with ASP.NET MVC3.
I couldn't find the reason
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
[HttpPost]
public ActionResult Index(string text)
{
string[] url = { "http://www.msnbc.com", "http://www.yahoo.com",
"http://www.nytimes.com", "http://www.washingtonpost.com",
"http://www.latimes.com", "http://www.newsday.com" };
Task<string[]> webTask = this.GetWordCounts(url, text);
string[] results = null;
try
{
results = webTask.Result;
}
catch (AggregateException e)
{
}
return View("Index", results);
}
//Taken from MSDN
Task<string[]> GetWordCounts(string[] urls, string name)
{
TaskCompletionSource<string[]> tcs = new TaskCompletionSource<string[]>();
WebClient[] webClients = new WebClient[urls.Length];
object m_lock = new object();
int count = 0;
List<string> results = new List<string>();
for (int i = 0; i < urls.Length; i++)
{
webClients[i] = new WebClient();
#region callback
// Specify the callback for the DownloadStringCompleted
// event that will be raised by this WebClient instance.
webClients[i].DownloadStringCompleted += (obj, args) =>
{
if (args.Cancelled == true)
{
tcs.TrySetCanceled();
return;
}
else if (args.Error != null)
{
// Pass through to the underlying Task
// any exceptions thrown by the WebClient
// during the asynchronous operation.
tcs.TrySetException(args.Error);
return;
}
else
{
// Split the string into an array of words,
// then count the number of elements that match
// the search term.
string[] words = null;
words = args.Result.Split(' ');
string NAME = name.ToUpper();
int nameCount = (from word in words.AsParallel()
where word.ToUpper().Contains(NAME)
select word)
.Count();
// Associate the results with the url, and add new string to the array that
// the underlying Task object will return in its Result property.
results.Add(String.Format("{0} has {1} instances of {2}", args.UserState, nameCount, name));
}
// If this is the last async operation to complete,
// then set the Result property on the underlying Task.
lock (m_lock)
{
count++;
if (count == urls.Length)
{
tcs.TrySetResult(results.ToArray());
}
}
};
#endregion
// Call DownloadStringAsync for each URL.
Uri address = null;
try
{
address = new Uri(urls[i]);
// Pass the address, and also use it for the userToken
// to identify the page when the delegate is invoked.
webClients[i].DownloadStringAsync(address, address);
}
catch (UriFormatException ex)
{
// Abandon the entire operation if one url is malformed.
// Other actions are possible here.
tcs.TrySetException(ex);
return tcs.Task;
}
}
// Return the underlying Task. The client code
// waits on the Result property, and handles exceptions
// in the try-catch block there.
return tcs.Task;
}
this is my view - for now I have hard coded keyword as microsoft
#using (Html.BeginForm("Index", "Home", new { text = "Microsoft" }))
{
<input type="submit" />
}
Update: It stays forever and inside the try block of Index Post method
I would recommend you using an AsyncController for this task to avoid jeopardizing ASP.NET worker threads which is one the worst thing that might happen to an ASP.NET application => running out of worker threads. It's like running out of fuel in the middle of the desert. You most certainly die.
So let's start by writing an extension method that will allow us converting the legacy WebClient event based pattern into the new task based pattern:
public static class TaskExtensions
{
public static Task<string> DownloadStringAsTask(this string url)
{
var tcs = new TaskCompletionSource<string>(url);
var client = new WebClient();
client.DownloadStringCompleted += (sender, args) =>
{
if (args.Error != null)
{
tcs.SetException(args.Error);
}
else
{
tcs.SetResult(args.Result);
}
};
client.DownloadStringAsync(new Uri(url));
return tcs.Task;
}
}
Armed with this extension method in hand we could now define a view model that will basically reflect the requirements of our view:
public class DownloadResultViewModel
{
public string Url { get; set; }
public int WordCount { get; set; }
public string Error { get; set; }
}
Then we move on to an asyncrhonous controller that will contain 2 actions: a standard synchronous Index action that will render the search form and an asynchronous Search action that will perform the actual work:
public class HomeController : AsyncController
{
public ActionResult Index()
{
return View();
}
[AsyncTimeout(600000)]
[HttpPost]
public void SearchAsync(string searchText)
{
AsyncManager.Parameters["searchText"] = searchText;
string[] urls =
{
"http://www.msnbc.com",
"http://www.yahoo.com",
"http://www.nytimes.com",
"http://www.washingtonpost.com",
"http://www.latimes.com",
"http://www.unexistentdomainthatwillcrash.com",
"http://www.newsday.com"
};
var tasks = urls.Select(url => url.DownloadStringAsTask());
AsyncManager.OutstandingOperations.Increment(urls.Length);
Task.Factory.ContinueWhenAll(tasks.ToArray(), allTasks =>
{
var results =
from task in allTasks
let error = task.IsFaulted ? task.Exception.Message : null
let result = !task.IsFaulted ? task.Result : string.Empty
select new DownloadResultViewModel
{
Url = (string)task.AsyncState,
Error = error,
WordCount = result.Split(' ')
.Where(x => string.Equals(x, searchText, StringComparison.OrdinalIgnoreCase))
.Count()
};
AsyncManager.Parameters["results"] = results;
AsyncManager.OutstandingOperations.Decrement(urls.Length);
});
}
public ActionResult SearchCompleted(IEnumerable<DownloadResultViewModel> results)
{
return View("index", results);
}
}
Now we define an ~/Views/Home/Index.cshtml view that will contain the search logic as well as the results:
#model IEnumerable<DownloadResultViewModel>
#using (Html.BeginForm("search", null, new { searchText = "politics" }))
{
<button type="submit">Search</button>
}
#if (Model != null)
{
<h3>Search results</h3>
<table>
<thead>
<tr>
<th>Url</th>
<th>Word count</th>
</tr>
</thead>
<tbody>
#Html.DisplayForModel()
</tbody>
</table>
}
And of course the corresponding display template that will be rendered automatically for each element of our model (~/Views/Shared/DisplayTemplates/DownloadResultViewModel.cshtml):
#model DownloadResultViewModel
<tr>
<td>#Html.DisplayFor(x => x.Url)</td>
<td>
#if (Model.Error != null)
{
#Html.DisplayFor(x => x.Error)
}
else
{
#Html.DisplayFor(x => x.WordCount)
}
</td>
</tr>
Now, since the search operation could take quite a long time your users could quickly get bored without being able to use some of the other hundredths of functionalities that your webpage has to offer them.
In this case it is absolutely trivial to invoke the Search controller action using an AJAX request and showing a spinner to inform the users that their search is in progress but without freezing the webpage allowing them to do other things (without navigating away from the page obviously).
So let's do that, shall we?
We start by externalizing the results into a partial (~/Views/Home/_Results.cshtml) without touching at the display template:
#model IEnumerable<DownloadResultViewModel>
#if (Model != null)
{
<h3>Search results</h3>
<table>
<thead>
<tr>
<th>Url</th>
<th>Word count</th>
</tr>
</thead>
<tbody>
#Html.DisplayForModel()
</tbody>
</table>
}
and we adapt our ~/Views/Home/Index.cshtml view to use this partial:
#model IEnumerable<DownloadResultViewModel>
#using (Html.BeginForm("search", null, new { searchText = "politics" }))
{
<button type="submit">Search</button>
}
<div id="results">
#Html.Partial("_Results")
</div>
and of course the SearchCompleted controller action that must now return only the partial result:
public ActionResult SearchCompleted(IEnumerable<DownloadResultViewModel> results)
{
return PartialView("_Results", results);
}
Now all that's left is to write a simple javascript that will AJAXify our search form. So this could happen into a separate js that will reference in our layout:
$(function () {
$('form').submit(function () {
$.ajax({
url: this.action,
type: this.method,
success: function (results) {
$('#results').html(results);
}
});
return false;
});
});
Depending on whether you referenced this script in the <head> section or at the end of the body you might not need to wrap it in a document.ready. If the script is at the end you could remove the wrapping document.ready function from my example.
And the last part is to give some visual indication to the user that the site is actually performing a search. This could be done using a global ajax event handler that we might subscribe to:
$(function () {
$(document).ajaxStart(function () {
$('#results').html('searching ...');
});
});

Consuming RSS feeds in ASP and C#

I'm working on making a modification to a site built with ASP/C#, and one of the tasks was to add in the display of 2 RSS feeds - one from the site's internal blog, and the other from the site's Twitter account. However, I seem to continually get empty feeds from both, even though I've confirmed that I'm pointing to the correct URL of the feeds. My code is shown below.
private void GetTwitterRSS()
{
IEnumerable items = Cache["TwitterFeed"] as List<SyndicationItem>;
if (items == null)
{
try
{
SyndicationFeed blogFeed = SyndicationFeed.Load(XmlReader.Create("http://twitter.com/statuses/user_timeline/84668697.rss"));
items = blogFeed.Items;
}
catch
{
items = new List<SyndicationItem>();
}
Cache.Insert("TwitterFeed", items, null, DateTime.Now.AddMinutes(5.0),TimeSpan.Zero);
twitterrssRepeater.DataSource = items;
twitterrssRepeater.DataBind();
}
}
private void GetBlogRSS()
{
IEnumerable items = Cache["BlogFeed"] as List<SyndicationItem>;
if (items == null)
{
try
{
SyndicationFeed blogFeed = SyndicationFeed.Load(XmlReader.Create("http://www.rentseeker.ca/blog/?feed=rss2"));
items = blogFeed.Items;
}
catch
{
items = new List<SyndicationItem>();
}
Cache.Insert("BlogFeed", items, null, DateTime.Now.AddHours(1.0),TimeSpan.Zero);
blogrssRepeater.DataSource = items;
blogrssRepeater.DataBind();
}
}
protected string DisplayBlogFeedItem(SyndicationItem item)
{
return string.Format(#"<p>{1}</p><p><strong>{2}</strong></p><p>{3}</p>",
FormatPublishDate(item.PublishDate.DateTime),
item.Title.Text,
item.Summary.Text);
}
protected string DisplayTwitterFeedItem(SyndicationItem item)
{
return string.Format(#"<li>{1}</li>",
item.Title.Text);
}
The code on the page is:
<ul>
<asp:ListView ID="twitterrssRepeater" runat="server">
<ItemTemplate>
<%# DisplayTwitterFeedItem((Container as ListViewDataItem).DataItem as System.ServiceModel.Syndication.SyndicationItem) %>
</ItemTemplate>
</asp:ListView>
</ul>
and
<asp:ListView ID="blogrssRepeater" runat="server">
<ItemTemplate>
<%# DisplayBlogFeedItem((Container as ListViewDataItem).DataItem as System.ServiceModel.Syndication.SyndicationItem) %>
</ItemTemplate>
</asp:ListView>
Clearly, I'm missing something. From what I've read, I understand that I'm supposed to authenticate myself in order to view a Twitter feed - I have the credentials, but am not sure how to pass them into SyndicationFeed when I load it.
Any tips, suggestions, or direction for further information is greatly appreciated.
Here's a simple example I would use to receive my Twitter feed (I'm only getting name, update title & id)
public class TwitterFeed
{
public string Name { get; set; }
public string Title { get; set; }
public string Id { get; set; }
}
Then the method to get the feed
public List<TwitterFeed> GetTwitterFeed(string name)
{
List<TwitterFeed> list = new List<TwitterFeed>();
XmlReader reader = XmlReader.Create(string.Format("http://search.twitter.com/search.atom?q=to:{0}", name));
SyndicationFeed feed = SyndicationFeed.Load(reader);
var tweetItems = from item in feed.Items
select new TwitterFeed()
{
Name = item.Authors.First().Name,
Title = item.Title.Text,
Id = item.Id
};
return tweetItems.ToList();
}
Hope that helps
SyndicationFeed.Items is not a List, but implements IEnumerable interface, so instead of
IEnumerable items = Cache["BlogFeed"] as List<SyndicationItem>;
use the following line:
IEnumerable items = Cache["BlogFeed"] as IEnumerable<SyndicationItem>;

Resources