C-Sharp Connection Example
From RETS Community Wiki
Please read: This example, using libRETS, shows a query pulling all listings with statuses of Active, Active CNT Misc, and Active CNT House, using a Visual Studio 05 (2.0) console application. The query uses system names from the metadata to reference the resource and class items.
Since we needed to pull all listings every day to update the real estate website, and this was impossible in one pull (due to a sort of RETS-imposed governor), we have it batched with the offset. Depending on the time of day, it will pull 300 at a time until it has exhausted the results of the query, and this quantity may differ with the association. A code gen was used to create a class to hold our sql server table fields to easily reference in mapping RETS fields to our db table. You'll see reference to this in Populate() as "currentlisting.(columnname)".
Please let me know if anything seems out of place or confusing. This is my first wiki posting, and there might be a formatting issue in the display of my code.
In your app.config or equivalent:
<appSettings> <clear/> <add key="RetsUrl" value="*1"/> <add key="RetsUserAgent" value="*2"/> <add key="RetsUserName" value="*3" /> <add key="RetsPassword" value="*4"/> <add key="ListingPhotoSavePath" value="C:\Inetpub\wwwroot\homeview\house_photo\"/> </appSettings>
- 1 = your association's login url. you can probably find it here: http://www.rapattoni.com/supp/mls/rets/rets_servers.asp
- 2 = user agent should be supplied by the association who purchased the rets server
- 3 = user name should be supplied by the association who purchased the rets server
- 4 = password should be supplied by the association who purchased the rets server
In the console app (this part is in vb)
Imports System.Configuration Imports System.Collections.Generic Module RetsDownload <MTAThread()> _ Sub Main() Dim url As String = ConfigurationManager.AppSettings("RetsUrl") Dim userAgent As String = ConfigurationManager.AppSettings("RetsUserAgent") Dim userName As String = ConfigurationManager.AppSettings("RetsUserName") Dim pass As String = ConfigurationManager.AppSettings("RetsPassword") Using retsHelper As New RetsHelper(url, userAgent, userName, pass) retsHelper.DownloadAllListings() End Using End Sub
In the C# class associated with the vb console app.
This console application has references set for librets-dotnet.dll, System, System.configuration, System.Data, System.Drawing, System.Transactions, and System.Xml. They may not all apply to the below code. My application also pulls photos, which will be in another post. Also important to note: the librets-pinvoke.dll needs to be in the root of the application, but does not need to be set as a reference. But since it is a C library, and is not COM or .Net compliant, the Copy to Output Directory property of this dll in your Solution Explorer should be set to Copy if newer, so it will be added to either the Debug or Release folder under your bin when the project builds.
namespace (Assoc Name).(site app is for) { public class RetsHelper : IDisposable { #region Properties /// <summary> /// Contains the rets session connection. /// </summary> internal RetsSession Session { get { return _sess; } set { _sess = value; } } private RetsSession _sess; #endregion #region Constructors public RetsHelper(string url, string userAgent, string userName, string password) { this.Session = new RetsSession(url); this.Session.SetUserAgent(userAgent); try { //Log in to RETS bool loginResult = this.Session.Login(userName, password); if (!loginResult) { Console.WriteLine("\nLogin to RETS Failed at " + DateTime.Now); } else { Console.WriteLine("\nLogin to RETS Succeeded at " + DateTime.Now); } } catch (Exception ex) { Console.WriteLine(ex.Message); } } #endregion #region Instance Methods /// <summary> /// Gets search results for a given query. /// </summary> /// <param name="searchType">Resource from rets metadata</param> /// <param name="searchClass">Class from rets metadata</param> /// <param name="query">RETS query to run.</param> /// <param name="offset">Record number to start at. This is 1-based, not zero-based.</param> /// <returns>Results of query.</returns> internal SearchResultSet GetRetsSearchResults(string searchType, string searchClass, string query, int offset) { using (SearchRequest search = this.Session.CreateSearchRequest( searchType, searchClass.ToString(), query)) { search.SetQueryType(SearchRequest.QueryType.DMQL2); search.SetStandardNames(false); search.SetOffset(offset); SearchResultSet results = this.Session.Search(search); return results; } } /// <summary> /// Downloads all listings, starting at the given offset. This method will recurse if needed. /// </summary> /// <param name="propType"></param> /// <param name="offset">Starting record of results. This is 1-based, not zero-based.</param> public void DownloadAllListings(string propType, int offset) { try { // get the records using System names. using (SearchResultSet results = GetRetsSearchResults("Property", propType, "(StreetNumber=0+),(Status=|A,C,M)", offset)) { // get the results as a list of objects. ListingCollection list = Populate(results); // save all records. list.SaveAll(); Console.WriteLine("\nSaving listings to sql db by the batch. Offset = " + offset); // process other info for the records. //currently just pulls & writes image files for listing photos. // Code in second example on RETS Wiki //ProcessListings(list); // check to see if the list finished to the end. int totalProcessed = list.Count + offset; if (results.GetCount() > totalProcessed) { // recurse if needed. DownloadAllListings(propType, totalProcessed); } } } catch (Exception ex) { Console.WriteLine(ex.Message); } } /// <summary> /// Populates a ListingCollection from a RETS result set. /// </summary> /// <param name="results">ResultSet to create the ListingCollection from.</param> /// <returns>ListingCollection representing the result set. Will return /// an empty collection if no records.</returns> private ListingCollection Populate(SearchResultSet results) { ListingCollection listings = new ListingCollection(); while (results.HasNext()) { //sample db mapping currentListing.AddrNumber = results.GetString("StreetNumber"); currentListing.AddrDirection = results.GetString("StreetDirection"); currentListing.AddrStreet = results.GetString("StreetName"); listings.Add(currentListing); } return listings; } #endregion #region IDisposable Members /// <summary> /// Logout of the RETS session. /// </summary> public void Dispose() { try { Session.Logout(); } finally { Session.Dispose(); } } #endregion } }
