Full Trust European Hosting

BLOG about Full Trust Hosting and Its Technology - Dedicated to European Windows Hosting Customer

European Umbraco Hosting - HostForLIFE.eu :: Tips Importing Wordpress Posts to Umbraco

clock February 21, 2014 10:13 by author Peter

Wordpress on the other hand is PHP, and I just suck at that. So there you go... Anyhow, after setting up my document types in Umbraco I needed to figure out how to get all my old content into the new site. Wordpress offers to export the entire content as xml, so that part was easy. The exported file was 3Mb, mainly because of some sort of screwed up tags back from when I was using the Ultimate Tag Warrior (I will miss the cool plugin names from Wordpress), which spit out a whole lot of empty tags.

The exported format is basically an RSS feed, but with some extra elements added by wordpress. One of those is an <excerpts:encoded> element, which does not have a namespace declaration at the top, thus making it invalid xml. So I needed to fix this before handling the file in my import routine. I just added it to the rss element:

<rss version="2.0"

xmlns:content="http://purl.org/rss/1.0/modules/content/"

xmlns:excerpt="http://purl.org/rss/1.0/modules/excerpt/"

xmlns:wfw="http://wellformedweb.org/CommentAPI/"

xmlns:dc="http://purl.org/dc/elements/1.1/"

xmlns:wp="http://wordpress.org/export/1.0/">

Sweet, now the xml is all nice and tidy and ready to be imported. So, how to do the import? Well, I decided to do it through the Umbraco API using a dashboard usercontrol. To get the content from the XML file, I chose to go with Linq2Xml which is pretty neat for navigating through the XML file. First thing I did was to disable some Lucene lock, because it made my import fail due to the number of operations done. I also set the script timeout value a bit high just to be sure:

Server.ScriptTimeout = 300;

Lucene.Net.Store.FSDirectory.SetDisableLocks(true);  

Now, to load the Xml file. Pretty easy. I later added the possibility to enter the XML in a textarea instead, thus the commented out line:

XDocument loaded = XDocument.Load(Server.MapPath("~/usercontrols/wordpress.2009-08-01.xml"));

XNamespace wpns = XNamespace.Get("http://wordpress.org/export/1.0/");

XNamespace contentns = XNamespace.Get("http://purl.org/rss/1.0/modules/content/");

var q = from c in loaded.Descendants("item")

  where (string)c.Element(wpns + "post_type") == "post"

  select c;

So now I got all my blogposts in the variable "q". time to feed them into Umbraco. It's not too nicely structured, but it does the job, and it's a one time deal, so no need to go crazy here.

DocumentType dt = DocumentType.GetByAlias("BlogPost");

User author = User.GetUser(0);

foreach (XElement item in q)

{

string posttitle = (string)item.Element("title");

string legacyurl = ((string)item.Element("link")).Replace("", string.Empty);

string legacyid = (string)item.Element(wpns + "post_id");

string posturlnodename = Server.UrlDecode((string)item.Element(wpns + "post_name"));

string postbody = (string)item.Element(contentns + "encoded");

string posttags = string.Empty;

DateTime createdate = DateTime.Parse((string)item.Element(wpns + "post_date"));

int i = 0;

foreach (XElement tag in item.Elements("category"))

{

if ((string)tag.Attribute("domain") == "tag" && !string.IsNullOrEmpty((string)tag.Attribute("nicename")))

{

if (i > 0)

 {

   posttags += ",";

 }

   posttags += (string)tag.Attribute("nicename");

   i++;

}

}

Document doc = Document.MakeNew(posturlnodename, dt, author, 1049);

doc.getProperty("blogPostTitle").Value = posttitle;

doc.getProperty("blogPostBody").Value = WordpressPostParser.ParseCodeBlocks(WordpressPostParser.ChangeImageUrls(WordpressPostParser.CreateParagraphTags(postbody)));

doc.getProperty("blogPostLegacyUrl").Value = legacyurl;

doc.getProperty("blogPostLegacyID").Value = legacyid;

doc.CreateDateTime = createdate;

if (!string.IsNullOrEmpty(posttags))

{

umbraco.editorControls.tags.library.addTagsToNode(doc.Id, posttags, "default");

doc.getProperty("blogPostTags").Value = posttags;

}

doc.Publish(author);

umbraco.library.UpdateDocumentCache(doc.Id);

//comments here...

foreach (XElement comment in item.Elements(wpns + "comment"))

{

if ((string)comment.Element(wpns + "comment_approved") == "1")

{

string commentAuthor = (string)comment.Element(wpns + "comment_author");

string commentEmail = (string)comment.Element(wpns + "comment_author_email");

string commentUrl = (string)comment.Element(wpns + "comment_author_url");

string commentIP = (string)comment.Element(wpns + "comment_author_IP");

string commentBody = (string)comment.Element(wpns + "comment_content");

DateTime commentDate = DateTime.Parse((string)comment.Element(wpns + "comment_date"));       

Document commentdoc = Document.MakeNew(commentAuthor, DocumentType.GetByAlias("BlogComment"), author, doc.Id);

commentdoc.getProperty("blogCommentAuthor").Value = commentAuthor;

commentdoc.getProperty("blogCommentAuthorEmail").Value = commentEmail;

commentdoc.getProperty("blogCommentAuthorURL").Value = commentUrl;

commentdoc.getProperty("blogCommentAuthorIP").Value = commentIP;

commentdoc.getProperty("blogCommentBody").Value = commentBody;

commentdoc.CreateDateTime = commentDate;

commentdoc.Publish(author);

umbraco.library.UpdateDocumentCache(commentdoc.Id);

}

}

}

I am using some external methods to parse the body text of the posts. This is because Wordpress doesn't save html, but puts in linebreaks and renders paragraph tags at render time... brrrr... There are also some [source] tags leftover from the syntax highlighter plugin that I need to change:

These are the three methods I am using to parse the text:

public static string CreateParagraphTags(string postbody)

{

StringBuilder sb = new StringBuilder();

sb.Append("<p>");

sb.Append(postbody.Replace("\n\n", "</p><p>"));

sb.Append("</p>");

return sb.ToString();

}

public static string ChangeImageUrls(string postbody)

{

string parsedstring = Regex.Replace(postbody, "src=\"/wp-content", "src=\"/media/images", RegexOptions.Singleline);

return Regex.Replace(parsedstring, "href=\"/wp-content", "href=\"/media/images", RegexOptions.Singleline);

}

public static string ParseCodeBlocks(string postbody)

{

Regex regPattern = new Regex(@"(\[source(.*?)\])(.*?)(\[/source\])", RegexOptions.Singleline);

Dictionary<string, string> replaceValues = new Dictionary<string, string>();

int i = 0;

foreach (Match match in regPattern.Matches(postbody))

{

string code = match.Groups[3].Value;

if (code.Contains("<"))

{

code = code.Replace("<", "&lt;").Replace(">", "&gt;");

}

postbody = postbody.Replace(match.Value, string.Format("[[[replacecode{0}]]]", i));

replaceValues.Add(string.Format("[[[replacecode{0}]]]", i), "<pre>" + code + "</pre>");

i++;

}

foreach (KeyValuePair<string, string> replaceValue in replaceValues)

{

postbody = postbody.Replace(replaceValue.Key, replaceValue.Value);

}

return postbody;

}

It's not perfect. For example it added some strange <p> tags inside my code blocks, but no more than I could handle by doing manual updates. For these methods I added some unit tests. It is just so much nicer to work with RegEx when you have tests to see if you are breaking existing matches while changing this stuff.



European HostForLIFE.eu Proudly Launches Windows Server 2012 R2 Hosting

clock February 17, 2014 10:19 by author Peter

HostForLIFE.eu proudly launches the support of Windows Server 2012 R2 on all their newest Windows Server environment. On Windows Server 2012 R2 hosted by HostForLIFE.eu, you can try their new and improved features that deliver extremely high levels of uptime and continuous server availability start from €3.00/month.

Microsoft recently released it’s latest operating system Windows Server 2012 R2 to global customers. Microsoft Windows Server 2012 R2 is much more than just another service pack; adding new features that make it easier to build cloud applications and services in your datacenter.

Delivering on the promise of a modern datacenter, modern applications, and people-centric IT, Windows Server 2012 R2 provides a best-in-class server experience that cost-effectively cloud-optimizes your business. When you optimize your business for the cloud with Windows Server 2012 R2 hosting, you take advantage of your existing skillsets and technology investments.

You also gain all the Microsoft experience behind building and operating private and public clouds – right in the box. Windows Server 2012 R2 offers an enterprise-class, simple and cost-effective solution that’s application-focused and user centric.

Further information and the full range of features Windows Server 2012 R2 Hosting can be viewed here: http://hostforlife.eu/European-Windows-Server-2012-R2-Hosting

About Company
HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. HostForLIFE.eu deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.



DotNetNuke 7.2 Hosting - HostForLIFE.eu : Creating a webservice in DotNetNuke 7

clock February 10, 2014 12:22 by author Peter

I have recently been assigned to built a DotNetNuke web service to allow a windows application (or any type of web client for that matter) the ability to manage DotNetNuke user accounts (create, change roles, delete, retrieve email address, etc.). Since I had a hard time finding a correct code sample or documentation that actually applies to DotNetNuke 7 and accessing it without being previously logged in to DotNetNuke 7 Hosting, it was difficult to built anything. I finally found out how to do it correctly so I tough I would put my efforts to some use and write a blog post explaining how to do it step by step.

The basics

That said, let's begin by the basics and just make a publicly accessible web service that allows anyone to ping the web service and get a pong back. For that we will use the new DotNetNuke 7 Services Framework which makes it quite simple if you know how to use it. In order to make a web service that will work withing DotNetNuke 7, you will need to fire up Visual Studio and create a Class Library project (c# or VB but all examples here will be in c#). That done, we will then reference some required DotNetNuke 7 required libraries (using the Add Reference dialog box), here's the list:

DotNetNuke.dll

DotNetNuke.Web.dll

System.Net.Http.dll

System.Net.Http.Formatting.dll

System.Web.Http.dll

Then we also need to reference the System.Web class from the .NET tab of the same dialog box. Finally, we neet to set the output path of the project to the DotNetNuke bin directory and we are ready to code. Here is the code, the explanations follow:

using System.Net;

using System.Net.Http;

using System.Web.Http;

using DotNetNuke.Web.Api;

namespace MyService

{

public class PingController : DnnApiController

{

 [AllowAnonymous]

 [HttpGet]

public HttpResponseMessage PublicPing()

{

return Request.CreateResponse(HttpStatusCode.OK, "Pong!");

}

}

public class RouteMapper : IServiceRouteMapper

{

public void RegisterRoutes(IMapRoute mapRouteManager)

{

mapRouteManager.MapHttpRoute("MyService", "default", "{controller}/{action}", new[]{"MyService"});

}

}

}

We simply start with some using statements for our requirements as shown above. We create a namespace for our service and whatever name we use here will be part of the url. I used MyService just for this example but use any name that makes sense for your service. Now we create a public class for our controller. You can create multiple controllers if you need to and the controller is just a group of related actions that make sense to group together. In my real project I have a PingController for testing purposes, a UsersController for any actions that relate to user accounts etc. Just use a name that makes sense since it will also show up in the url. Two things to be careful here:

The name of your controller must end with the word Controller but only what comes before it will show in the url, so for PingController, only Ping will show in the url path.

It must inherit DnnApiController so it will use the DotNetNuke Services Framework.

Then we create the actual action, in our case, PublicPing. It is just a simple method which return an HttpResponseMessage and can have a few attributes. By default the new services framework will respond only to host users and you need to explicitly allow other access rights if needed, in this case the [AllowAnonymous] makes this method (or action if you prefer) available to anyone without credentials. The second attribute, [HttpGet] will make this action respond to HTTP GET verb, which is usually used when requesting some date from the web server.

Finally in that action, you insert whatever code you action needs to do, in this case just return the string "Pong!", just remember that you need to return an HttpResponseMessage and not a string or int or other object. So, our controller and action is done, now we just need to map that to an actual URL and that what the last part of the previous code does. In essence this code tells DotNetNuke to map a certain url pattern to the methods defined in your class. You can use that code as is just replacing MyService by whatever your service name is.

Testing:
That's all there is to it, your service is ready!  To test it, first compile it, then just navigate to http://yourdomain/DesktopModules/MyService/API/Ping/PublicPing and you should see "Pong!" in your browser as a response.

Passing parameters

The basic code above is working but it doesn't do anything useful. Lets add something more useful by creating an action that will give us the email address for a specific user id.

Again, here's the code and the explanations will follow (place the code inside the same namespace as the previous one):

public class UsersController : DnnApiController

{

[RequireHost]

[HttpGet]

public HttpResponseMessage GetEmail(int userid)

{

DotNetNuke.Entities.Users.UserInfo ui;

ui = DotNetNuke.Entities.Users.UserController.GetUserById(PortalSettings.PortalId, userid);

return Request.CreateResponse(HttpStatusCode.OK, ui.Email);

}

}

First we build a UsersController class that will hold all actions related to user accounts, it is not absolutely necessary, you can have many actions in the same controller, however since this action is not at all related to our PingController, let'a make a new one more descriptive. We then make a GetEmail action (method) that will accept a userid parameter. The [RequireHost] parameter here will make it accessible only to host users, we'll see later other authentication options.

The code in the method itself is pretty much self explanatory. The only interesting thing to note here is that because our class inherits DnnApiController, we already have a PortalSettings object available. That's the big advantage of making use of the DotNetNuke Services Framework. You will have a ModuleInfo object to represent your module (if there is one with the same name as your service, which is not necessary such in this case), a PortalSettings object that represents the portal at the domain name used to access the service (portal alias) and finally a UserInfo object representing the user that accessed the web service.

Testing:
If we now navigate to http://yourdomain/MyService/API/Users/GetEmail?userid=2 you should receive the email address back from the server unless of course that userid does not exist, make sure to test with a userid that actually exists for that portal. If you where not previously connected with a host account, then you will be asked for credentials.

Limiting access to certain roles

Ok, that works but you need to give host credentials to any person needing to use your webservice. To avoid that you can replace [RequireHost] by [DnnAuthorize(StaticRoles="Administrators")] which will limit access to administrators. Better but you still need to give them an admin account. So the easy way to give only limited access would be to create a new role in DotNetNuke just for your web service and replace Administrators by that specific role name in the authentication parameter.

 



About HostForLIFE

HostForLIFE is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2019 Hosting, ASP.NET 5 Hosting, ASP.NET MVC 6 Hosting and SQL 2019 Hosting.


Tag cloud

Sign in