PSC > .NET - ASP.NETSource code, tools and tricks for .NET Frameworkhttp://puresourcecode.com/dotnet/
http://www.rssboard.org/rss-specificationBlogEngine.NET 3.3.6.0en-GBhttp://puresourcecode.com/dotnet/opml.axdhttp://www.dotnetblogengine.net/syndication.axdHenryPSC > .NET0.0000000.000000Connect ASP.NET MVC 4.6.2 project to IdentityServer4<p>I have a website running on <strong>ASP.NET MVC 4.5.2</strong>. I have an <strong>IdentityServer4</strong> server running but when I try and authenticate against it I get an:</p>
<pre><code>invalid_request</code></pre>
<p>I googled a bit but I can&rsquo;t find a solution. Finally, I found the way.</p>
<p>First, in your IdentityServer4 you have to create a new client:</p>
<pre class="brush: csharp;">public static IEnumerable GetClients() {
return new List&lt;client&gt; {
new Client {
ClientId = "yourid",
AllowedScopes = new List&lt;string&gt; { "openid" },
AllowedGrantTypes = GrantTypes.Hybrid,
RedirectUris = new List { "http://yoururl/signin-oidc" },
}
}
}</pre>
<p>When you added the new client, you can update your other MVC project. Under <strong>App_Start</strong> open <strong>Startup.Auth.cs</strong> and add this code:</p>
<pre class="brush: csharp;">using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
namespace PSC
{
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
Authority = "https://yourIdentityServerUrl",
ClientId = "yourid",
ResponseType = "id_token code",
SignInAsAuthenticationType = "Cookies",
RedirectUri = "http://yoururl/signin-oidc",
Scope = "openid",
});
}
}
}
</pre>
<p>You have to add a Nuget package called <strong>Microsoft.Owin.Security.OpenIdConnect</strong>.</p>
<p>Happy coding!</p>http://puresourcecode.com/dotnet/post/2018/10/30/connect-asp-net-mvc-4-6-2-project-to-identityserver41
enrico.rossini.uk@live.comhttp://puresourcecode.com/dotnet/post/2018/10/30/connect-asp-net-mvc-4-6-2-project-to-identityserver41#commenthttp://puresourcecode.com/dotnet/post.aspx?id=670729aa-e170-41ce-94e1-149b7710b715Tue, 30 Oct 2018 08:27:00 -0800ASP.NETC#MVChenryhttp://puresourcecode.com/dotnet/pingback.axdhttp://puresourcecode.com/dotnet/post.aspx?id=670729aa-e170-41ce-94e1-149b7710b7150http://puresourcecode.com/dotnet/trackback.axd?id=670729aa-e170-41ce-94e1-149b7710b715http://puresourcecode.com/dotnet/post/2018/10/30/connect-asp-net-mvc-4-6-2-project-to-identityserver41#commenthttp://puresourcecode.com/dotnet/syndication.axd?post=670729aa-e170-41ce-94e1-149b7710b715Connect ASP.NET MVC 4.6.2 project to IdentityServer4<p>I have a website running on <strong>ASP.NET MVC 4.5.2</strong>. I have an <strong>IdentityServer4</strong> server running but when I try and authenticate against it I get an:</p>
<pre><code>invalid_request</code></pre>
<p>I googled a bit but I can&rsquo;t find a solution. Finally, I found the way.</p>
<p>First, in your IdentityServer4 you have to create a new client:</p>
<pre class="brush: csharp;">public static IEnumerable GetClients() {
return new List&lt;client&gt; {
new Client {
ClientId = "yourid",
AllowedScopes = new List&lt;string&gt; { "openid" },
AllowedGrantTypes = GrantTypes.Hybrid,
RedirectUris = new List { "http://yoururl/signin-oidc" },
}
}
}</pre>
<p>When you added the new client, you can update your other MVC project. Under <strong>App_Start</strong> open <strong>Startup.Auth.cs</strong> and add this code:</p>
<pre class="brush: csharp;">using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
namespace PSC
{
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
Authority = "https://yourIdentityServerUrl",
ClientId = "yourid",
ResponseType = "id_token code",
SignInAsAuthenticationType = "Cookies",
RedirectUri = "http://yoururl/signin-oidc",
Scope = "openid",
});
}
}
}
</pre>
<p>You have to add a Nuget package called <strong>Microsoft.Owin.Security.OpenIdConnect</strong>.</p>
<p>Happy coding!</p>http://puresourcecode.com/dotnet/post/2018/10/30/connect-asp-net-mvc-4-6-2-project-to-identityserver4
enrico.rossini.uk@live.comhttp://puresourcecode.com/dotnet/post/2018/10/30/connect-asp-net-mvc-4-6-2-project-to-identityserver4#commenthttp://puresourcecode.com/dotnet/post.aspx?id=d63103d9-68d0-4233-a719-75253224ff9fTue, 30 Oct 2018 08:27:00 -0800ASP.NETC#MVChenryhttp://puresourcecode.com/dotnet/pingback.axdhttp://puresourcecode.com/dotnet/post.aspx?id=d63103d9-68d0-4233-a719-75253224ff9f0http://puresourcecode.com/dotnet/trackback.axd?id=d63103d9-68d0-4233-a719-75253224ff9fhttp://puresourcecode.com/dotnet/post/2018/10/30/connect-asp-net-mvc-4-6-2-project-to-identityserver4#commenthttp://puresourcecode.com/dotnet/syndication.axd?post=d63103d9-68d0-4233-a719-75253224ff9fGravatar Tag Helper for .NET Core 2.1<p>A <strong>tag helper</strong> is any class that implements the <code>ITagHelper</code> interface. However, when you create a tag helper, you generally derive from <code>TagHelper</code>, doing so gives you access to the <code>Process</code> method.</p>
<p>In your <strong>ASP.NET Core project</strong>, create a folder to hold the Tag Helpers called <em>TagHelpers</em>. The <em>TagHelpers</em> folder is <em>not</em> required, but it's a reasonable convention. Now let's get started writing some simple tag helpers.</p>
<p><a href="http://puresourcecode.com/dotnet/image.axd?picture=gravatar-taghelper.png"><img style="margin: 0px auto; float: none; display: block; background-image: none;" title="gravatar-taghelper" src="http://puresourcecode.com/dotnet/image.axd?picture=gravatar-taghelper_thumb.png" alt="gravatar-taghelper" width="644" height="122" border="0" /></a></p>
<ul>
<li>
<p>Tag helpers use a naming convention that targets elements of the root class name (minus the <em>TagHelper</em> portion of the class name). In this example, the root name of <strong>Gravatar</strong>TagHelper is <em>email</em>, so the <code>&lt;email&gt;</code> tag will be targeted. This naming convention should work for most tag helpers, later on I'll show how to override it.</p>
</li>
<li>
<p>The <code>EmailTagHelper</code> class derives from <code>TagHelper</code>. The <code>TagHelper</code> class provides methods and properties for writing Tag Helpers.</p>
</li>
<li>
<p>The overridden <code>Process</code> method controls what the tag helper does when executed. The <code>TagHelper</code> class also provides an asynchronous version (<code>ProcessAsync</code>) with the same parameters.</p>
</li>
<li>
<p>The context parameter to <code>Process</code> (and <code>ProcessAsync</code>) contains information associated with the execution of the current HTML tag.</p>
</li>
<li>
<p>The output parameter to <code>Process</code> (and <code>ProcessAsync</code>) contains a stateful HTML element representative of the original source used to generate an HTML tag and content.</p>
</li>
</ul>
<h2>GravatarTagHelper</h2>
<pre class="brush: csharp;">using Microsoft.AspNetCore.Razor.TagHelpers;
using System;
using System.Security.Cryptography;
using System.Text;
using PSC.Enums;
namespace PSC.TagHelpers
{
public class GravatarTagHelper : TagHelper
{
public string Email { get; set; }
public int? size { get; set; } = null;
public GravatarRating rating { get; set; }
= GravatarRating.Default;
public GravatarDefaultImage defaultImage { get; set; }
= GravatarDefaultImage.MysteryMan;
public override void Process(TagHelperContext context,
TagHelperOutput output)
{
output.TagName = "img";
output.Attributes.SetAttribute("alt", Email + " gravatar");
var url = new StringBuilder("//www.gravatar.com/avatar/", 90);
url.Append(GetEmailHash(Email));
var isFirst = true;
Action&lt;string, string&gt; addParam = (p, v) =&gt;
{
url.Append(isFirst ? '?' : '&amp;');
isFirst = false;
url.Append(p);
url.Append('=');
url.Append(v);
};
if (size != null)
{
if (size &lt; 1 || size &lt; 512)
throw new ArgumentOutOfRangeException("size", size,
"Must be null or between 1 and 512, inclusive.");
addParam("s", size.Value.ToString());
}
if (rating != GravatarRating.Default)
addParam("r", rating.ToString().ToLower());
if (defaultImage != GravatarDefaultImage.Default)
{
if (defaultImage == GravatarDefaultImage.Http404)
addParam("d", "404");
else if (defaultImage == GravatarDefaultImage.Identicon)
addParam("d", "identicon");
if (defaultImage == GravatarDefaultImage.MonsterId)
addParam("d", "monsterid");
if (defaultImage == GravatarDefaultImage.MysteryMan)
addParam("d", "mm");
if (defaultImage == GravatarDefaultImage.Wavatar)
addParam("d", "wavatar");
}
output.Attributes.SetAttribute("src", url.ToString());
if (size != null)
{
output.Attributes.SetAttribute("width", size.ToString());
output.Attributes.SetAttribute("height", size.ToString());
}
}
private static string GetEmailHash(string email)
{
if (email == null)
return new string('0', 32);
email = email.Trim().ToLower();
var emailBytes = Encoding.ASCII.GetBytes(email);
var hashBytes = new MD5CryptoServiceProvider()
.ComputeHash(emailBytes);
var hash = new StringBuilder();
foreach (var b in hashBytes)
hash.Append(b.ToString("x2"));
return hash.ToString();
}
}
}
</pre>
<h2>GravatarDefaultImage</h2>
<pre class="brush: csharp;">namespace PSC.Enums
{
public enum GravatarDefaultImage
{
///
/// The default value image. That is, the image returned
/// when no specific default value is included
/// with the request.
/// At the time of authoring, this image is the Gravatar icon.
///
Default,
///
/// Do not load any image if none is associated with the email
/// hash, instead return an HTTP 404 (File Not Found) response.
///
Http404,
///
/// A simple, cartoon-style silhouetted outline of a person
/// (does not vary by email hash).
///
MysteryMan,
///
/// A geometric pattern based on an email hash.
///
Identicon,
///
/// A generated 'monster' with different colors, faces, etc.
///
MonsterId,
///
/// Generated faces with differing features and backgrounds.
///
Wavatar
}
}
</pre>
<h2>GravatarRating</h2>
<pre class="brush: csharp;">namespace PSC.Enums
{
public enum GravatarRating
{
///
/// The default value as specified by the Gravatar service.
/// That is, no rating value is specified
/// with the request. At the time of authoring,
/// the default level was &lt;see cref="G"/&gt;.
///
Default,
///
/// Suitable for display on all websites with any audience type.
/// This is the default.
///
G,
///
/// May contain rude gestures, provocatively dressed individuals,
/// the lesser swear words, or mild violence.
///
Pg,
///
/// May contain such things as harsh profanity, intense violence,
/// nudity, or hard drug use.
///
R,
///
/// May contain hardcore sexual imagery or
/// extremely disturbing violence.
///
X
}
}
</pre>
<p>To make the <code>GravatarTagHelper</code> class available to all our Razor views, add the <code>addTagHelper</code> directive to the <em>Views/_ViewImports.cshtml</em> file:</p>
<pre class="brush: xml;">@using AuthoringTagHelpers
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, PSC
</pre>
<p>Now in your page, you have access to your <strong>gravatar tag</strong>!</p>http://puresourcecode.com/dotnet/post/2018/06/18/Gravatar-Tag-Helper-for-NET-Core-21
enrico.rossini.uk@live.comhttp://puresourcecode.com/dotnet/post/2018/06/18/Gravatar-Tag-Helper-for-NET-Core-21#commenthttp://puresourcecode.com/dotnet/post.aspx?id=7df77b98-87db-408d-90c3-9cce99f709f0Mon, 18 Jun 2018 15:39:00 -0800.NET CoreASP.NETC#gravatartaghelpershenryhttp://puresourcecode.com/dotnet/pingback.axdhttp://puresourcecode.com/dotnet/post.aspx?id=7df77b98-87db-408d-90c3-9cce99f709f00http://puresourcecode.com/dotnet/trackback.axd?id=7df77b98-87db-408d-90c3-9cce99f709f0http://puresourcecode.com/dotnet/post/2018/06/18/Gravatar-Tag-Helper-for-NET-Core-21#commenthttp://puresourcecode.com/dotnet/syndication.axd?post=7df77b98-87db-408d-90c3-9cce99f709f0Render in MVC a link with image and text<p> Hi guys, I want in MVC to render a text with an image as an <strong>ActionLink</strong>. For creating a simple anchor tag, we use <strong>Html.ActionLink()</strong> helper which generates anchor tag for us. </p> <p> If you want to create something a bit more complicated, you must create you own component. For this reason, I created the following code. It allows you to create an anchor with an image and a text. </p> <pre class="brush: csharp;">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace PSC.MVC.Helpers
{
public static class CustomHtmlHelpers
{
/// <summary>
/// Enum ImageAndText
/// </summary>
public enum ImageAndText
{
/// <summary>
/// Image on the left, text on the right
/// </summary>
ImageOnTheLeft,
/// <summary>
/// Text on the left, image on the right
/// </summary>
ImageOnTheRight
}
/// <summary>
/// Images the action link.
/// </summary>
/// <param name="htmlHelper">The HTML helper.</param>
/// <param name="linkText">The link text.</param>
/// <param name="action">The action.</param>
/// <param name="controller">The controller.</param>
/// <param name="routeValues">The route values.</param>
/// <param name="htmlAttributes">The HTML attributes.</param>
/// <param name="imageSrc">The image source.</param>
/// <param name="alternateText">The alternate text.</param>
/// <param name="textStyle">The text style.</param>
/// <param name="imageStyle">The image style.</param>
/// <param name="imagePosition">The image position.</param>
/// <returns>IHtmlString.</returns>
public static IHtmlString ImageActionLink(
this HtmlHelper htmlHelper, string linkText, string action,
string controller, object routeValues, object htmlAttributes,
string imageSrc, string alternateText = "",
string textStyle = "", string imageStyle = "",
ImageAndText imagePosition = ImageAndText.ImageOnTheLeft)
{
var urlHelper = new UrlHelper(
htmlHelper.ViewContext.RequestContext);
// create the image
var img = new TagBuilder("img");
img.Attributes.Add("src",
VirtualPathUtility.ToAbsolute(imageSrc));
if (!string.IsNullOrEmpty(alternateText))
img.Attributes.Add("alt", alternateText.Trim());
if (!string.IsNullOrEmpty(imageStyle))
img.Attributes.Add("style", imageStyle);
// create a render for the image and the text
string render = "";
if (imagePosition == ImageAndText.ImageOnTheLeft)
render = img.ToString(TagRenderMode.SelfClosing) + linkText;
else
render = linkText + img.ToString(TagRenderMode.SelfClosing);
// create the anchor with image and text
var anchor = new TagBuilder("a") {
InnerHtml = render
};
if (!string.IsNullOrEmpty(textStyle))
anchor.AddCssClass(textStyle);
// add reference to the anchor
anchor.Attributes["href"] = urlHelper.Action(action,
controller,
routeValues);
anchor.MergeAttributes(new RouteValueDictionary(htmlAttributes));
return MvcHtmlString.Create(anchor.ToString());
}
}
}
</pre>
<p>
In your MVC code you have to add:
</p>
<pre class="brush: csharp;">
@using PSC.MVC.Helpers;
</pre>
and then you can call your component:
<pre class="brush: csharp;">
@Html.ImageActionLink("Your text", "Index", "Home", null, null,
"~/Content/images/img.png", "Logo", "navbar-brand",
"width: 40px;")
</pre>http://puresourcecode.com/dotnet/post/2017/04/23/Render-in-MVC-a-link-with-image-and-text
enrico.rossini.uk@live.comhttp://puresourcecode.com/dotnet/post/2017/04/23/Render-in-MVC-a-link-with-image-and-text#commenthttp://puresourcecode.com/dotnet/post.aspx?id=a45567b9-3f79-4689-8268-a2131046ada7Sun, 23 Apr 2017 18:48:26 -0800C#MVCASP.NETcomponentsmvchelpershtmlhenryhttp://puresourcecode.com/dotnet/pingback.axdhttp://puresourcecode.com/dotnet/post.aspx?id=a45567b9-3f79-4689-8268-a2131046ada70http://puresourcecode.com/dotnet/trackback.axd?id=a45567b9-3f79-4689-8268-a2131046ada7http://puresourcecode.com/dotnet/post/2017/04/23/Render-in-MVC-a-link-with-image-and-text#commenthttp://puresourcecode.com/dotnet/syndication.axd?post=a45567b9-3f79-4689-8268-a2131046ada7ASP.NET LinkButton: children disappears after postback<p>I have a <strong>LinkButton</strong> with image and label inside it or tags i and span as in the following picture.<a href="http://puresourcecode.com/dotnet/image.axd?picture=example_linkbutton.png"><img title="example_linkbutton" style="float: left; margin: 0px 10px 0px 0px; display: inline" alt="example_linkbutton" src="http://puresourcecode.com/dotnet/image.axd?picture=example_linkbutton_thumb.png" width="101" align="left" height="45" /></a></p> <p>The code in the page is: </p> <pre class="brush: xml;">&lt;asp:LinkButton ID=&quot;LinkButton1&quot; runat=&quot;server&quot;&gt;
&lt;i class=&quot;glyphicon glyphicon-plus&quot;&gt;&lt;/i&gt;
&lt;span class=&quot;js-add-button&quot; runat=&quot;server&quot; id=&quot;Span1&quot;&gt;Add New&lt;/span&gt;
&lt;/asp:LinkButton&gt;</pre>
<p>After a postback everything inside the LinkButton disappeared. I've spent two days to understand why and the solution is very easy. </p>
<pre class="brush: xml;">&lt;asp:LinkButton ID=&quot;LinkButton1&quot; runat=&quot;server&quot;&gt;
&lt;i class=&quot;glyphicon glyphicon-plus&quot; runat=&quot;server&quot;&gt;&lt;/i&gt;
&lt;span class=&quot;js-add-button&quot; runat=&quot;server&quot; id=&quot;Span1&quot;&gt;Add New&lt;/span&gt;
&lt;/asp:LinkButton&gt;</pre>
<p>The tag i doesn't have runat=&quot;server&quot; and for that you lost all content inside the LinkButton. </p>
<p>Happy coding! </p>http://puresourcecode.com/dotnet/post/2016/05/03/ASPNET-LinkButton-children-disappears-after-postback
enrico.rossini.uk@live.comhttp://puresourcecode.com/dotnet/post/2016/05/03/ASPNET-LinkButton-children-disappears-after-postback#commenthttp://puresourcecode.com/dotnet/post.aspx?id=c11450b7-f4f4-4886-b065-f483c9cf997dTue, 3 May 2016 16:51:02 -0800ASP.NETlinkbuttonpostbackchildrenhenryhttp://puresourcecode.com/dotnet/pingback.axdhttp://puresourcecode.com/dotnet/post.aspx?id=c11450b7-f4f4-4886-b065-f483c9cf997d0http://puresourcecode.com/dotnet/trackback.axd?id=c11450b7-f4f4-4886-b065-f483c9cf997dhttp://puresourcecode.com/dotnet/post/2016/05/03/ASPNET-LinkButton-children-disappears-after-postback#commenthttp://puresourcecode.com/dotnet/syndication.axd?post=c11450b7-f4f4-4886-b065-f483c9cf997dHow to upload a file in an ASP.Net MVC page<p>For this example, I’m using a controller named “HomeController”, with the view “Index”. When you click the “Submit” button on the view, it will be submitted to the “Save” method of HomeController.</p> <h3>Index.cshtml</h3> <pre class="brush: csharp;">@using(Html.BeginForm(&quot;Save&quot;, &quot;Home&quot;, FormMethod.Post,
new {enctype = &quot;multipart/form-data&quot;}))
{
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;File:&lt;/td&gt;
&lt;td&gt;
&lt;input type=&quot;file&quot; name=&quot;UploadedFile&quot; /&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;2&quot;&gt;
&lt;input type=&quot;submit&quot; name=&quot;Submit&quot; value=&quot;Submit&quot;/&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
}</pre>
<p>Notice the two additional parameters for BeginForm</p>
<pre class="brush: csharp;">FormMethod.Post, new {enctype = &quot;multipart/form-data&quot;}</pre>
<p>You need those to have the file included in the HTTP Post action to the Save method on the controller. Other than that, you just need a file input control, with a unique name attribute set.</p>
<h3>HomeController</h3>
<pre class="brush: csharp;">using System;
using System.Web;
using System.Web.Mvc;
namespace FileUpload.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Save(FormCollection formCollection)
{
if(Request != null)
{
HttpPostedFileBase file = Request.Files[&quot;UploadedFile&quot;];
if((file != null) &amp;&amp; (file.ContentLength &gt; 0) &amp;&amp;
!string.IsNullOrEmpty(file.FileName))
{
string fileName = file.FileName;
string fileContentType = file.ContentType;
byte[] fileBytes = new byte[file.ContentLength];
file.InputStream.Read(fileBytes, 0,
Convert.ToInt32(file.ContentLength));
string pth = Path.GetFileName(fileName);
// change the folder
file.SaveAs(Server.MapPath(&quot;~/Uploads&quot;) + &quot;/&quot; + pth);
}
}
return View(&quot;Index&quot;);
}
}
}</pre>
<p>The Request object is a base object for handling HTTP requests. Since we set the <strong>FormMethod</strong> and enctype in the view, we have access to the file that was submitted on the page.</p>
<p>If the Request object isn’t null, we can check for the file by getting the <strong>HttpPostedFileBase</strong> from the Request object’s list of files, using its name (which is why a unique name was required for the file input control on the view).</p>
<p>Then we do some checking, to make sure the file actually has data, and get its information.</p>
<p>If you’re going to save the files somewhere (which is probably why you’re letting people upload files), then you’re going to need a way to display it for them later. To display a file within a browser, you need to know its <strong>ContentType</strong>. This will let the browser display it in the correct way.</p>
<p>With the byte array of the file’s contents, you can either save it to the database, in a varbinary column [for SQL Server], or write it out to disk, or some other document storage location.</p>
<p>Where you should save the files depends on what you’re going to do with them, how large they are, and what type of file they are.</p>
<blockquote>
<p>If you see an error like </p>
<p><i>The SaveAs method is configured to require a rooted path, and the path '~/App_data/Uploads/1.pdf' is not rooted.</i></p>
<p><b>Description: </b>An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
<br /><b>Exception Details: </b>System.Web.HttpException: The SaveAs method is configured to require a rooted path, and the path '~/App_data/Uploads/1.pdf' is not rooted.</p>
<p>the problem is in the SaveAs function. You must pass a valid full path such as “C:\Uploads\Test\1.png”. For this reason I created in the root of the project a folder called Uploads and use Server.MapPath to find the full path.</p>
</blockquote>
<p>Happy coding!</p>http://puresourcecode.com/dotnet/post/2016/02/23/How-to-upload-a-file-in-an-ASPNet-MVC-page
enrico.rossini.uk@live.comhttp://puresourcecode.com/dotnet/post/2016/02/23/How-to-upload-a-file-in-an-ASPNet-MVC-page#commenthttp://puresourcecode.com/dotnet/post.aspx?id=9c112859-751f-4aea-b030-9275fd6b9d92Tue, 23 Feb 2016 13:14:27 -0800ASP.NETMVCC#FormMethodHttpPostedFileBaseContentTypeuploadhenryhttp://puresourcecode.com/dotnet/pingback.axdhttp://puresourcecode.com/dotnet/post.aspx?id=9c112859-751f-4aea-b030-9275fd6b9d920http://puresourcecode.com/dotnet/trackback.axd?id=9c112859-751f-4aea-b030-9275fd6b9d92http://puresourcecode.com/dotnet/post/2016/02/23/How-to-upload-a-file-in-an-ASPNet-MVC-page#commenthttp://puresourcecode.com/dotnet/syndication.axd?post=9c112859-751f-4aea-b030-9275fd6b9d92Customize Json result in Web API<p>If you work with Visual Studio 2015 and WebAPI, this short post is for you!</p> <p>We have to make our Web API project easy to debug so, I’m going to remove the XML formatter. I’m doing that because I’m in a test project and I’d like to see the response in the browser. The easily way to force the response to Json for all Web API requests is to remove the XML. Obviously you shouldn't do it in production.</p> <h3>Global.asax</h3> <pre class="brush: csharp;">var formatters = GlobalConfiguration.Configuration.Formatters;
formatters.Remove(formatters.XmlFormatter);</pre>
<p>Now we can start change the setting for all Json responses accessing to <b>GlobalConfiguration.Configuration.Formatters.JsonFormatter</b>. </p>
<p>In the following examples I’ll use always the class below (create it under Models folder): </p>
<pre class="brush: csharp;">using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace PSC.Models
{
public class MapModel
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Username { get; set; }
public DateTime Birthdate { get; set; }
public Uri Website { get; set; }
public int Age { get; set; }
public double Salary { get; set; }
[JsonIgnore]
public string IgnoreProperty { get; set; }
}
}</pre>
<p>Now we customize the Global.asax again to reply with the correct format. Change the Global.asax as following code: </p>
<pre class="brush: csharp;">using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace PSC
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// start change the setting for all Json responses accessing to
// GlobalConfiguration.Configuration.Formatters.JsonFormatter
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
// How can we indent the json response?
json.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
// How can we change the case in the response?
json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
// How can we manage the null in the response?
json.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
// How can we change the DateTime format?
json.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat;
// How can we change the TimeZone format?
//json.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
// How can we change the Culture of the serializer?
// json.SerializerSettings.Culture = new CultureInfo("en-GB");
var formatters = GlobalConfiguration.Configuration.Formatters;
formatters.Add(json);
}
}
}</pre>
<p>Then under <b>Controllers</b> create a new one and add the following code: </p>
<pre class="brush: csharp;">using Newtonsoft.Json.Serialization;
using PSC.Models;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Web.Http;
namespace PSC.Controllers
{
public class MapController : ApiController
{
public HttpResponseMessage Get()
{
IList&lt;mapmodel&gt; result = new List&lt;mapmodel&gt;();
result.Add(new MapModel
{
Age = 34,
Birthdate = DateTime.Now,
Firstname = "Enrico",
Lastname = "Rossini",
IgnoreProperty = "This text should not appear in the reponse",
Salary = 1000,
Username = "enrico",
Website = new Uri("http://puresourcecode.com")
});
var formatter = new JsonMediaTypeFormatter();
var json = formatter.SerializerSettings;
json.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat;
json.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
json.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
json.Formatting = Newtonsoft.Json.Formatting.Indented;
json.ContractResolver = new CamelCasePropertyNamesContractResolver();
json.Culture = new CultureInfo("en-GB");
return Request.CreateResponse(HttpStatusCode.OK, result, formatter);
}
}
}</pre>
<p>The result is pretty cool! </p>
<p><a href="http://puresourcecode.com/dotnet/image.axd?picture=webapi-json.png"><img width="644" height="388" title="webapi-json" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: none; padding-top: 0px; padding-left: 0px; border-left: 0px; margin: 0px auto; display: block; padding-right: 0px" alt="webapi-json" src="http://puresourcecode.com/dotnet/image.axd?picture=webapi-json_thumb.png" border="0"></a></p>
<p>Happy coding! </p>http://puresourcecode.com/dotnet/post/2016/02/17/Customize-Json-result-in-Web-API
enrico.rossini.uk@live.comhttp://puresourcecode.com/dotnet/post/2016/02/17/Customize-Json-result-in-Web-API#commenthttp://puresourcecode.com/dotnet/post.aspx?id=bf1058e3-7e44-4f1e-943f-6f63c8928aa2Wed, 17 Feb 2016 12:11:00 -0800ASP.NETC#WebAPIjsonvisual studio 2015newtonsofthenryhttp://puresourcecode.com/dotnet/pingback.axdhttp://puresourcecode.com/dotnet/post.aspx?id=bf1058e3-7e44-4f1e-943f-6f63c8928aa21http://puresourcecode.com/dotnet/trackback.axd?id=bf1058e3-7e44-4f1e-943f-6f63c8928aa2http://puresourcecode.com/dotnet/post/2016/02/17/Customize-Json-result-in-Web-API#commenthttp://puresourcecode.com/dotnet/syndication.axd?post=bf1058e3-7e44-4f1e-943f-6f63c8928aa2Creating a URL shortener using ASP.NET WepAPI and MVC: error handling<p>In the two previous post I discussed about the <a href="http://puresourcecode.com/dotnet/post/Creating-a-URL-shortener-using-ASPNET-WepAPI-and-MVC">first step to creare this application</a> and the <a href="http://puresourcecode.com/dotnet/post/Creating-a-URL-shortener-using-ASPNET-WepAPI-and-MVC-implementing-the-business-layer">implementation of the business logic</a>. Now we can implement the error handling.</p> <p>We have two custom exception classes: </p> <ul> <li>ShorturlConflictException (when a segment already exists) and </li> <li>ShorturlNotFoundException (when a segment isn’t found in the database). </li> </ul> <p>There is also a third type: an <strong>unexpected exception</strong>, for example when there is no database connection. Normally, the user will see these errors. We have to build a mechanism where these exceptions are caught and a nice error page is shown, corresponding to the type of error, with the corresponding HTTP status code. </p> <p>We need to add a filter to the Web project. Add a new folder called “Filters” and add a “ShorturlExceptionFilter” class.</p> <pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using PSC.Shorturl.Web.Exceptions;
namespace PSC.Shorturl.Web.Filters
{
public class ShorturlErrorFilter : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
HttpStatusCode code = HttpStatusCode.InternalServerError;
var ex = filterContext.Exception;
string viewName = &quot;Error500&quot;;
if (ex is ShorturlNotFoundException)
{
code = HttpStatusCode.NotFound;
viewName = &quot;Error404&quot;;
}
if (ex is ShorturlConflictException)
{
code = HttpStatusCode.Conflict;
viewName = &quot;Error409&quot;;
}
filterContext.Result = new ViewResult()
{
ViewName = viewName
};
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = (int)code;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
}
}</pre>
<p>This filter extends from the HandleErrorAttribute, and overrides the OnException method. In this method we do our own exception handling. If the exception is one of our own exceptions, a 404 or 409 is returned, else a 500 is returned. At the bottom of the method we tell the context that the exception is handled, and the current response (the ugly error page) will be cleared and our custom views (which are defined below) will be returned. </p>
<p>Add the following views in the “Views\Shared” folder: </p>
<h3>Error404.cshtml</h3>
<pre class="brush: csharp;">@{
ViewBag.Title = &quot;Not Found&quot;;
}
&lt;h2&gt;Not Found&lt;/h2&gt;
&lt;p&gt;The resource you've requested isn't found.&lt;/p&gt;</pre>
<h3>Error409.cshtml</h3>
<pre class="brush: csharp;">@{
ViewBag.Title = &quot;Conflict&quot;;
}
&lt;h2&gt;Conflict&lt;/h2&gt;
&lt;p&gt;The name you've chosen already exists.&lt;/p&gt;</pre>
<h3>Error500.cshtml</h3>
<pre class="brush: csharp;">@{
ViewBag.Title = &quot;Error&quot;;
}
&lt;h2&gt;Error&lt;/h2&gt;
&lt;p&gt;An unexpected error occured.&lt;/p&gt;</pre>
<p>The only thing we have to do now is add the filter to our FilterConfig class (under App_Start). In the FilterConfig class, replace the existing method with this method: </p>
<pre class="brush: csharp;">using System.Web;
using System.Web.Mvc;
using PSC.Shorturl.Web.Filters;
namespace PSC.Shorturl.Web
{
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ShorturlErrorFilter());
filters.Add(new HandleErrorAttribute());
}
}
}</pre>
<p>Now, when there is an exception, a nice error page will be shown. Next post about WebApi integration. </p>http://puresourcecode.com/dotnet/post/2016/02/09/Creating-a-URL-shortener-using-ASPNET-WepAPI-and-MVC-error-handling
enrico.rossini.uk@live.comhttp://puresourcecode.com/dotnet/post/2016/02/09/Creating-a-URL-shortener-using-ASPNET-WepAPI-and-MVC-error-handling#commenthttp://puresourcecode.com/dotnet/post.aspx?id=155600d6-feb8-4250-a685-9abd2dc2656cTue, 9 Feb 2016 14:17:47 -0800ASP.NETC#MVCWebAPIshorturlunityentity frameworkjsonormexceptionhenryhttp://puresourcecode.com/dotnet/pingback.axdhttp://puresourcecode.com/dotnet/post.aspx?id=155600d6-feb8-4250-a685-9abd2dc2656c0http://puresourcecode.com/dotnet/trackback.axd?id=155600d6-feb8-4250-a685-9abd2dc2656chttp://puresourcecode.com/dotnet/post/2016/02/09/Creating-a-URL-shortener-using-ASPNET-WepAPI-and-MVC-error-handling#commenthttp://puresourcecode.com/dotnet/syndication.axd?post=155600d6-feb8-4250-a685-9abd2dc2656cCreating a URL shortener using ASP.NET WepAPI and MVC: implementing the business layer<p>In <a href="http://puresourcecode.com/dotnet/post/Creating-a-URL-shortener-using-ASPNET-WepAPI-and-MVC">my previsious post</a> I discussed the first implementation of this application. In this post I’m explained how to implement the business layer.</p> <p>First of all you make sure the Business project references the Data, Entities and Exceptions projects. In the Exceptions project you add two new classes:</p> <h3>ShorturlConflictException</h3> <pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PSC.Shorturl.Web.Exceptions
{
public class ShorturlConflictException : Exception
{
}
}
</pre>
<h3>ShorturlNotFoundException</h3>
<pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PSC.Shorturl.Web.Exceptions
{
public class ShorturlNotFoundException : Exception
{
}
}
</pre>
<p>We’ve implemented a stub for a business manager. The manager actually doesn’t do anything, but since we’ve implemented the database layer, it’s now possible to do some advanced stuff. Below you’ll see the new <em>IUrlManager</em> and <em>UrlManager</em>.</p>
<h3>IUrlManager</h3>
<pre class="brush: csharp;">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PSC.Shorturl.Web.Entities;
public interface IUrlManager
{
Task&lt;ShortUrl&gt; ShortenUrl(string longUrl, string ip, string segment = "");
Task&lt;Stat&gt; Click(string segment, string referer, string ip);
}
</pre>
<h3>UrlManager</h3>
<pre class="brush: csharp;">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PSC.Shorturl.Web.Data;
using PSC.Shorturl.Web.Entities;
using PSC.Shorturl.Web.Exceptions;
namespace PSC.Shorturl.Web.Business.Implementations
{
public class UrlManager : IUrlManager
{
public Task&lt;ShortUrl> ShortenUrl(string longUrl, string ip, string segment = "")
{
return Task.Run(() =>
{
using (var ctx = new ShorturlContext())
{
ShortUrl url;
url = ctx.ShortUrls.Where(u => u.LongUrl == longUrl).FirstOrDefault();
if (url != null)
{
return url;
}
if (!string.IsNullOrEmpty(segment))
{
if (ctx.ShortUrls.Where(u => u.Segment == segment).Any())
{
throw new ShorturlConflictException();
}
}
else
{
segment = this.NewSegment();
}
if (string.IsNullOrEmpty(segment))
{
throw new ArgumentException("Segment is empty");
}
url = new ShortUrl()
{
Added = DateTime.Now,
Ip = ip,
LongUrl = longUrl,
NumOfClicks = 0,
Segment = segment
};
ctx.ShortUrls.Add(url);
ctx.SaveChanges();
return url;
}
});
}
public Task&lt;Stat> Click(string segment, string referer, string ip)
{
return Task.Run(() =>
{
using (var ctx = new ShorturlContext())
{
ShortUrl url = ctx.ShortUrls.Where(u => u.Segment == segment).FirstOrDefault();
if (url == null)
{
throw new ShorturlNotFoundException();
}
url.NumOfClicks = url.NumOfClicks + 1;
Stat stat = new Stat()
{
ClickDate = DateTime.Now,
Ip = ip,
Referer = referer,
ShortUrl = url
};
ctx.Stats.Add(stat);
ctx.SaveChanges();
return stat;
}
});
}
private string NewSegment()
{
using (var ctx = new ShorturlContext())
{
int i = 0;
while (true)
{
string segment = Guid.NewGuid().ToString().Substring(0, 6);
if (!ctx.ShortUrls.Where(u => u.Segment == segment).Any())
{
return segment;
}
if (i > 30)
{
break;
}
i++;
}
return string.Empty;
}
}
}
}
</pre>
<p>
You’ll see two new methods here: Click and NewSegment. The Click method will be executed any time anyone clicks on a short URL; some data (like the refering website) will be stored in the database. The NewSegment method creates a unique segment for our short URL. If it hasn’t found a valid segment in 30 loops, an empty string will be returned (this situation will be very rare though). The ShortenUrl method now actually shortens a long URL and stores it, together with a generated segment, in the database.
</p>
<p>
As you can see, any time a database action is executed, a new context object is created. When there are changes to the data, SaveChanges() is executed on the context at the end.
</p>
<h2>Putting it in the UrlController</h2>
<p>
Now we have a working business layer, we can call the business methods in the URL controller. Below, you see the updated Index() method:
</p>
<pre class="brush: csharp;">
public async Task&lt;ActionResult> Index(Url url)
{
if (ModelState.IsValid)
{
ShortUrl shortUrl = await this._urlManager.ShortenUrl(url.LongURL, Request.UserHostAddress);
url.ShortURL = string.Format("{0}://{1}{2}{3}", Request.Url.Scheme,
Request.Url.Authority, Url.Content("~"),
shortUrl.Segment);
}
return View(url);
}
</pre>
<p>
The controller asks the UrlManager for a new ShortUrl. When all went well, a full URL with the segment at the end will be created. At the moment there is only one problem; when we navigate to that URL, nothing happens, so we have to implement another method in the UrlController which handles the redirects. You’ll see this method below:
</p>
<pre class="brush: csharp;">
public async Task<ActionResult> Click(string segment)
{
string referer = Request.UrlReferrer != null ? Request.UrlReferrer.ToString() : string.Empty;
Stat stat = await this._urlManager.Click(segment, referer, Request.UserHostAddress);
return this.RedirectPermanent(stat.ShortUrl.LongUrl);
}
</pre>
<p>
The only thing we have to do now is tell MVC that when we go to http://yourapp/segment, we wind up in that specific method. Below, you’ll see the new RegisterRoutes method of the class RouteConfig.
</p>
<pre class="brush: csharp;">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace PSC.Shorturl.Web
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Click",
url: "{segment}",
defaults: new { controller = "Url", action = "Click" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Url", action = "Index",
id = UrlParameter.Optional }
);
}
}
}
</pre>
<p>
It’s very important that the “Click” route stands above the “Default” route.
</p>
<p>
Another nice thing our URL manager supports is adding a custom segment, for example http://yourapp/mysite. We have to modify three things for that:
</p>
<h2>1. Update the Url model</h2>
<pre class="brush: csharp;">
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace PSC.Shorturl.Web.Models
{
public class Url
{
[Required]
public string LongURL { get; set; }
public string ShortURL { get; set; }
public string CustomSegment { get; set; }
}
}
</pre>
<h2>2. Update the Index method</h2>
<pre class="brush: csharp;">
public async Task&lt;ActionResult> Index(Url url)
{
if (ModelState.IsValid)
{
ShortUrl shortUrl = await this._urlManager.ShortenUrl(url.LongURL,
Request.UserHostAddress, url.CustomSegment);
url.ShortURL = string.Format("{0}://{1}{2}{3}", Request.Url.Scheme,
Request.Url.Authority, Url.Content("~"),
shortUrl.Segment);
}
return View(url);
}
</pre>
<h2>3. Update the view</h2>
<pre class="brush: csharp;">
@model PSC.Shorturl.Web.Models.Url
@{
ViewBag.Title = "URL shortener";
}
&lt;h2>Shorten a URL&lt;/h2>
@Html.ValidationSummary()
@using (Html.BeginForm())
{
&lt;div class="form-group">
@Html.TextBoxFor(model => model.LongURL, new { placeholder = "URL you would like to have shortened",
@class = "form-control" })
&lt;/div>
&lt;div class="form-group">
@Html.TextBoxFor(model => model.CustomSegment, new { placeholder = "If you like, fill in a custom word for your short URL",
@class = "form-control" })
&lt;/div>
if (!string.IsNullOrEmpty(Model.ShortURL))
{
&lt;div>
&lt;h3>&lt;a href="@Model.ShortURL" target="_blank">@Model.ShortURL&lt;/a>&lt;/h3>
&lt;/div>
}
&lt;input type="submit" class="btn btn-primary" value="Shorten" />
}
</pre>
<p>
After this is done, it looks like we have a basic, and functioning, URL shortener. We still have to add some error handling; when an error is thrown from within the business layer, a big old ugly error page will be shown to the user. This is not something we want, this is what we’re going to fix next. In the next post.
</p>
<p>Happy coding!</p>http://puresourcecode.com/dotnet/post/2016/02/09/Creating-a-URL-shortener-using-ASPNET-WepAPI-and-MVC-implementing-the-business-layer
enrico.rossini.uk@live.comhttp://puresourcecode.com/dotnet/post/2016/02/09/Creating-a-URL-shortener-using-ASPNET-WepAPI-and-MVC-implementing-the-business-layer#commenthttp://puresourcecode.com/dotnet/post.aspx?id=66a5fe13-8408-4f5e-b056-e6db04ce5bfaTue, 9 Feb 2016 13:39:51 -0800C#ASP.NETMVCWebAPIshorturlunityentity frameworkjsonormhenryhttp://puresourcecode.com/dotnet/pingback.axdhttp://puresourcecode.com/dotnet/post.aspx?id=66a5fe13-8408-4f5e-b056-e6db04ce5bfa2http://puresourcecode.com/dotnet/trackback.axd?id=66a5fe13-8408-4f5e-b056-e6db04ce5bfahttp://puresourcecode.com/dotnet/post/2016/02/09/Creating-a-URL-shortener-using-ASPNET-WepAPI-and-MVC-implementing-the-business-layer#commenthttp://puresourcecode.com/dotnet/syndication.axd?post=66a5fe13-8408-4f5e-b056-e6db04ce5bfaCreating a URL shortener using ASP.NET WepAPI and MVC<p>In this tutorial, I use several techniques and tools. I use Microsoft Visual Studio 2015 and the latest version of all components.</p> <ul> <li><strong>ASP.NET MVC</strong>: Microsoft’s modern web application framework. As the name says, it pushes you to use the MVC (<strong>model view controller</strong>) software design principle. </li> <li><strong>ASP.NET Web API</strong>: Web API and MVC are used together in many applications. With MVC, the HTML of the web pages are rendered on the server, and with Web API you can, like the name says, create an API. Web API also uses the MVC principle, but returns XML (or JSON, or YAML, or … whatever you want) instead of HTML. </li> <li><strong>Microsoft SQL</strong>: this is my primary database choice. </li> <li><strong>Entity Framework</strong>: this is my favourite ORM (object relational mapping) framework. With Entity Framework, you can create a database “code-first”, meaning that you can create classes (called entities) that represent the database and create the database based on those entities and its relations. When you’ve updated one of these entities, you can add a new migration, which means that the changes to your entities will be written to the database. </li> <li><strong>Unity</strong>: Unity is a dependency injection framework. You can read more on dependency injection and inversion of control later in this tutorial. </li> </ul> <h2>Basic project structure</h2> <p>If you didn’t know already, Visual Studio works with solutions. A solution can contain multiple projects. When a solution is compiled, a DLL (or EXE if it’s a WPF or Console application) is created. These DLLs, in case of an MVC application, are deployed to the server. A project can reference another project in the same solution, or assemblies compiled from another solution. A third way of adding references is using NuGet; this is a package manager for ASP.NET applications. Using this, you can add a connector to MySQL, Entity Framework, xUnit.net (testing framework) and many, many more to your solution. You can compare it to Composer (PHP) or npm (Node.js).</p> <p>Once you’ve started Visual Studio, go to <em>File</em> | <em>New</em> | <em>Project</em>. I always select “ASP.NET Web Application”. In the following dialog, select “MVC”, but also select “Web API”. On the right hand, change authentication to “No Authentication”, since we’re not going to use that (not for this tutorial though, maybe later). In the bottom fields, you can fill in the name and location of your solution. I call it “PSC.Shorturl.Web” (but call it anything you want). You can uncheck “Host in the cloud”, although I’m not sure what the difference is (I never hosted anything in Azure). You can now click OK.</p> <p>A basic MVC site is created now. Once you click the “Run” button at the top, you’ll already be able to browse the basic website. A local IIS web server is launched and your favourite browser will be opened with the MVC website.</p> <p><a href="http://puresourcecode.com/dotnet/image.axd?picture=ASPNET_MVC_FirstStart.png"><img width="644" height="440" title="ASPNET_MVC_FirstStart" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto; display: block; padding-right: 0px; border-top-width: 0px" alt="ASPNET_MVC_FirstStart" src="http://puresourcecode.com/dotnet/image.axd?picture=ASPNET_MVC_FirstStart_thumb.png" border="0"></a></p> <p>As you can see, there are some files and folders created for you in this project. I’m going to explain what these folders and files are.</p> <p><a href="http://puresourcecode.com/dotnet/image.axd?picture=ASPNET_MVC_Solution.png"><img width="359" height="434" title="ASPNET_MVC_Solution" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto; display: block; padding-right: 0px; border-top-width: 0px" alt="ASPNET_MVC_Solution" src="http://puresourcecode.com/dotnet/image.axd?picture=ASPNET_MVC_Solution_thumb.png" border="0"></a></p> <ul> <li><strong>App_Data</strong>: This folder is empty for now, but if you ever want to enable uploads on your websites, it’s best if they are placed here. </li> <li><strong>App_Start</strong>: this folder contains some classes which are needed to start up MVC and Web API when the application is first run. If you add new frameworks which need something of a setup, this can be placed in this folder. </li> <li><strong>Content</strong>: this folder contains your CSS files and images. </li> <li><strong>Controllers</strong>: this folder contains the controller classes of the MVC application. </li> <li><strong>fonts</strong>: as the name says, this folder contains fonts. </li> <li><strong>Models</strong>: this folder contains models which will be used to pass data from the controllers to the views. </li> <li><strong>Scripts</strong>: this folder contains (Java)script files. </li> <li><strong>Views</strong>: this folder contains the views for the MVC application. </li> <li><strong>Global.asax</strong>: this file is loaded when the application is started. In this file, the classes in the “<strong>App_Start</strong>” folder are called. </li> <li><strong>packages.config</strong>: if you’re going to add packages from NuGet to your project, a reference to that project will be added to this file. When someone else receives your code and tries to build our code, Visual Studio first downloads all packages defined in this file (else the build would fail because these DLLs aren’t available). </li> <li><strong>Web.config</strong>: this file contains general configuration for your application. Think of database connection strings, SMTP server settings etc. </li> </ul> <p>First, let’s open HomeController.cs in the folder Controllers. You’ll see this code:</p> <pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace PSC.Shorturl.Web.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
}</pre>
<p>&nbsp;</p>
<p>This method contains three methods. When the application is started, <strong>RouteConfig</strong> (which is located in App_Start) is read and mapped to the existing controllers. In this application it means that when you go to http://yourapp/Home/About, the method About in the <strong>HomeController</strong> will be executed. This is called <strong>convention over configuration</strong>; you don’t have to explicitly tell the application that you have added a new controller. This means that when you add a new controller, say UrlController with a method Shorten, this will be called when you go to http://yourapp/Url/Shorten. </p>
<p>You also see that the methods in this class return a <strong>View()</strong>. For example, when you browse to /Home/About, the View() searches in the folder Views to the file About.cshtml (can be another extension, but the file should be called “About”). Again, this is “convention over configuration”.</p>
<p>Every method in this controller returns an <strong>ActionResult</strong>. An ActionResult can be a view, but can also be a redirect (which we’ll use later when redirecting a short URL).</p>
<p>This default behaviour can be fine tuned, but I think that’s not necessary for now; I think it works fine this way.</p>
<p>Now that’s explained, let’s create a new controller. Right click the <strong>Controllers</strong> folder and create a new controller (MVC 5 Controller – Empty). I call it UrlController.</p>
<p><a href="http://puresourcecode.com/dotnet/image.axd?picture=ASPNET_MVC_AddController1.png"><img width="644" height="438" title="ASPNET_MVC_AddController1" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto; display: block; padding-right: 0px; border-top-width: 0px" alt="ASPNET_MVC_AddController1" src="http://puresourcecode.com/dotnet/image.axd?picture=ASPNET_MVC_AddController1_thumb.png" border="0"></a></p>
<p><a href="http://puresourcecode.com/dotnet/image.axd?picture=ASPNET_MVC_AddController2.png"><img width="644" height="448" title="ASPNET_MVC_AddController2" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto; display: block; padding-right: 0px; border-top-width: 0px" alt="ASPNET_MVC_AddController2" src="http://puresourcecode.com/dotnet/image.axd?picture=ASPNET_MVC_AddController2_thumb.png" border="0"></a></p>
<p>By adding a new controller, a new folder is also added in the “Views” folder; “Url”. In this folder, create a new view called “Index.cshtml”. This is the code for the view:</p>
<pre class="brush: csharp;">@{
ViewBag.Title = "Index";
}
&lt;h2&gt;Index&lt;/h2&gt;
This is the main URL shortening view. Here, we'll show our form later on.</pre>
<p>&nbsp;</p>
<p>On the top of the view, you see a syntax you may have never seen before. This is MVC’s template syntax: Razor. The property “Title” of “<strong>ViewBag</strong>” is set to “URL shortener”. ViewBag is used to pass data from one view to another. In this case, the title will be rendered between the title tags of the master layout. </p>
<p>If you start the application now and head to /Url/Index (or just /Url, because Index is assumed if the second part isn’t set; see <strong>RouteConfig.cs</strong>), you’ll see our newly created view rendered. Later on, this view will contain the form where users can fill in their long URL to be shortened, so when the root URL is reached, we would like the user to see this page, we don’t want them to go to http://yourapp/Url. To accomplish this open RouteConfig.cs. </p>
<pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace PSC.Shorturl.Web
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index",
id = UrlParameter.Optional }
);
}
}
}</pre>
<p>&nbsp;</p>
<p>This is the default route configuration. You’ll see that by default the HomeController and Index action are selected. Change “Home” to “Url”. Now, when we go to the root URL, we’ll see our newly created view.</p>
<p>This view is a bit empty for now. First, add a new class called “Url” to the folder “Models”. Like I’ve said before, a model is responsible for passing data between a View and a Controller. Below, you’ll see the model I’ve created:</p>
<pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace PSC.Shorturl.Web.Models
{
public class Url
{
public string LongURL { get; set; }
public string ShortURL { get; set; }
}
}</pre>
<p>&nbsp;</p>
<p>The model will contain the long URL and the short URL for now. When the user has filled in the URL he / she would like to have shortened, the LongURL property will be set and it will be sent to the business layer (which we will create lateron). The business layer will validate the URL and will return a short URL. The short URL will be set and the model will be returned to the view. </p>
<p>Now, let’s add a form to Index.cshtml.</p>
<pre class="brush: csharp;">@model PSC.Shorturl.Web.Models.Url
@{
ViewBag.Title = "URL shortener";
}
&lt;h2&gt;Shorten a URL&lt;/h2&gt;
@using (Html.BeginForm())
{
&lt;div class="form-group"&gt;
@Html.TextBoxFor(model =&gt; model.LongURL,
new { placeholder = "URL you would like to have shortened",
@class = "form-control" })
&lt;/div&gt;
&lt;input type="submit" class="btn btn-primary" value="Shorten" /&gt;
}</pre>
<p>&nbsp;</p>
<p>As you can see, I’ve added a “@model” reference at the top. The view now knows that it should use the class we’ve just created (you can call the model anywhere by using @Model in the view). Further on, you see we start a new HTML form. In this form we start a new TextBox, with a reference to the LongURL property in the class “Url”. The second parameter in this method is an anonymous object with several HTML attributes, like placeholder and class (class is prefixed with an “@” because it is a reserved keyword in ASP.NET, the application won’t work otherwise). The last line is a plain old HTML submit button. </p>
<p><a href="http://puresourcecode.com/dotnet/image.axd?picture=ASPNET_MVC_FirstScreen.png"><img width="644" height="421" title="ASPNET_MVC_FirstScreen" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto; display: block; padding-right: 0px; border-top-width: 0px" alt="ASPNET_MVC_FirstScreen" src="http://puresourcecode.com/dotnet/image.axd?picture=ASPNET_MVC_FirstScreen_thumb.png" border="0"></a></p>
<p>All very nice, but there is no logic at all at the moment. Let’s go back to UrlController.cs.</p>
<pre class="brush: csharp;">using PSC.Shorturl.Web.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace PSC.Shorturl.Web.Controllers
{
public class UrlController : Controller
{
[HttpGet]
public ActionResult Index()
{
Url url = new Url();
return View(url);
}
public ActionResult Index(Url url)
{
url.ShortURL = "http://www.puresourcecode.com";
return View(url);
}
}
}</pre>
<p>&nbsp;</p>
<p>You now see that I’ve created two methods with the same name. One which doesn’t have any parameters, one with a Url object as parameter. The first method will only be called when the user is first directed to the page. The second method is used when the user has pushed the submit button. MVC will serialize the data filled in on the form, place it in a URL object and pass it to that function. Here, we will be able read the original LongURL property and send it to the business layer. As of now, nothing happens with it and the ShortURL property is set to “http://www.google.com” hard coded. This is fine for now. The object with the ShortURL property set is being passed to the view, so we can read this property in the view now. If you place the snippet below in “Index.cshtml” underneath the textbox, you’ll see the shortened URL when you push the submit button. </p>
<pre class="brush: csharp;">if (!string.IsNullOrEmpty(Model.ShortURL))
{
&lt;div&gt;
lt;a href="@Model.ShortURL" target="_blank"&gt;@Model.ShortURL&lt;/a&gt;
&lt;/div&gt;
}</pre>
<p>&nbsp;</p>
<p>It would be nice to have a little validation. For now, it’s enough to validate that the user has actually filled in anything as long URL. So go back to "Url.cs" and change LongURL to this: </p>
<pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace PSC.Shorturl.Web.Models
{
public class Url
{
[Required]
public string LongURL { get; set; }
public string ShortURL { get; set; }
}
}</pre>
<p>&nbsp;</p>
<p>By placing this attribute directly above this property, MVC knows that this property should be set. Next, change the second Index method in UrlController.cs to this: </p>
<pre class="brush: csharp;">public ActionResult Index(Url url)
{
if (ModelState.IsValid)
{
url.ShortURL = "http://www.puresourcecode.com";
}
return View(url);
}</pre>
<p>&nbsp;</p>
<p>ModelState.IsValid checks if all validation requirements are met. If yes, set the ShortURL. Finally, we would like the user to get validation feedback. In “Index.cshtml”, place this piece of code anywhere you’d like (I place it directly beneath the H2 tags): </p>
<pre class="brush: csharp;">@Html.ValidationSummary()</pre>
<p>At this point, I deleted the HomeController and Home folder in the Views folder; we don’t need it for the now. </p>
<p>Now, it’s time to set up the other projects. Right click the solution and add new projects. The project I’m describing should be of the type “Class Library”. </p>
<p><a href="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_NewProject.png"><img width="695" height="531" title="ShortUrl_NewProject" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto; display: block; padding-right: 0px; border-top-width: 0px" alt="ShortUrl_NewProject" src="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_NewProject_thumb.png" border="0"></a></p>
<p><a href="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_ClassLibrary.png"><img width="644" height="448" title="ShortUrl_ClassLibrary" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto; display: block; padding-right: 0px; border-top-width: 0px" alt="ShortUrl_ClassLibrary" src="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_ClassLibrary_thumb.png" border="0"></a></p>
<ul>
<li><strong>PSC.Shorturl.Web.Business</strong>: this project will contain the interfaces and classes needed to execute numerous business actions; for example adding a new short URL to the database, searching a short URL etc. </li>
<li><strong><strong>PSC.Shorturl</strong>.Web.Data</strong>: this project will contain our data context for Entity Framework and the migrations will be saved in this project. </li>
<li><strong><strong>PSC.Shorturl</strong>.Web.Entities</strong>: this project will contain the entities (plain old classes) for our data structure. </li>
<li><strong><strong>PSC.Shorturl</strong>.Web.Exceptions</strong>: this project will contain custom exceptions. For example, when a specific URL isn’t found, an exception will be thrown and it will be caught by the MVC framework to show us a nice custom error page. </li>
</ul>
<p>So, now we’ve created all project we’re going to need to add several NuGet packages to the projects.</p>
<p><a href="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_NuGet.png"><img width="569" height="565" title="ShortUrl_NuGet" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto; display: block; padding-right: 0px; border-top-width: 0px" alt="ShortUrl_NuGet" src="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_NuGet_thumb.png" border="0"></a></p>
<p>Search and install the following packages. I’m going to describe in which projects every package has to be installed to.</p>
<p><a href="http://puresourcecode.com/dotnet/image.axd?picture=Shorturl_Nuget_packages.png"><img width="644" height="381" title="Shorturl_Nuget_packages" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto; display: block; padding-right: 0px; border-top-width: 0px" alt="Shorturl_Nuget_packages" src="http://puresourcecode.com/dotnet/image.axd?picture=Shorturl_Nuget_packages_thumb.png" border="0"></a></p>
<ul>
<li><strong>EntityFramework</strong>: the ORM which we’re going to use.
<ul>
<li>Business </li>
<li>Data </li>
<li>Entities </li>
<li>Web </li>
</ul>
</li>
<li><strong>Newtonsoft.Json</strong>: a nice Json serializer for ASP.NET. This will be needed by Web API later on.
<ul>
<li>Business </li>
<li>Data </li>
<li>Entities </li>
<li>Web </li>
</ul>
</li>
<li><strong>Unity</strong>, <strong>Unity bootstrapper for ASP.NET MVC</strong> &amp; <strong>Unity.WebAPI</strong>: this is an inversion of control (IoC) for ASP.NET. It is used for loose coupled web applications. I will explain this later on.
<ul>
<li>Web </li>
</ul>
</li>
</ul>
<p>The solution should be able to build now. If not, please leave a comment and maybe I can help you.</p>
<h3>Dependency injection</h3>
<p>Robust applications don’t have any hard coupling in their code. What I always like to do is constructor injection; whenever a controller (or any other class) is instantiated, you can fill in a few parameters in the constructor. These parameters are interfaces. </p>
<p>Unity, an inversion of control framework, finds out which implementation belongs to this interface, and injects it. With this framework, you don’t have hard coupling; there is only one place in your application where you fill in this interface/implementation mapping. Whenever you need to change the implementation (for example, you used Entity Framework, but want to switch to NHibernate), you just create a new class that implements that specific interface and you change the configuration for <strong>Unity</strong>. It might all sound a bit vague. Let’s try to setup Unity.</p>
<h4>1. The web project should reference all other projects</h4>
<p>Right click the web project and add a new reference.</p>
<p><a href="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_ReferencesMenu.png"><img width="685" height="751" title="ShortUrl_ReferencesMenu" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto; display: block; padding-right: 0px; border-top-width: 0px" alt="ShortUrl_ReferencesMenu" src="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_ReferencesMenu_thumb.png" border="0"></a></p>
<p><a href="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_References.png"><img width="644" height="446" title="ShortUrl_References" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto; display: block; padding-right: 0px; border-top-width: 0px" alt="ShortUrl_References" src="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_References_thumb.png" border="0"></a></p>
<h4>2. Add an interface IUrlManager and a class UrlManager (which implements IUrlManager)</h4>
<h5>IUrlManager</h5>
<pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PSC.Shorturl.Web.Business
{
public interface IUrlManager
{
Task&lt;string&gt; ShortenUrl(string longUrl);
}
}</pre>
<h5>UrlManager</h5>
<p>Create a folder named Implementations and under this folder create the following interface:</p>
<pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PSC.Shorturl.Web.Business.Implementations
{
public class UrlManager : IUrlManager
{
public Task&lt;string&gt; ShortenUrl(string longUrl)
{
return Task.Run(() =&gt;
{
return "http://www.puresourcecode.com";
});
}
}
}</pre>
<p>We have to tell the application somehow that when an implementation for IUrlManager is desired, a UrlManager should be injected. The method RegisterTypes in the class UnityConfig will look like this now: </p>
<pre class="brush: csharp;">using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using PSC.Shorturl.Web.Business;
using PSC.Shorturl.Web.Business.Implementations;
namespace PSC.Shorturl.Web.App_Start
{
/// &lt;summary&gt;
/// Specifies the Unity configuration for the main container.
/// &lt;/summary&gt;
public class UnityConfig
{
#region Unity Container
private static Lazy&lt;iunitycontainer&gt; container = new Lazy&lt;iunitycontainer&gt;(() =&gt;
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// &lt;summary&gt;
/// Gets the configured Unity container.
/// &lt;/summary&gt;
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
#endregion
/// &lt;summary&gt;Registers the type mappings with the Unity container.&lt;/summary&gt;
/// &lt;param name="container" /&gt;The unity container to configure.&lt;/param&gt;
/// &lt;remarks&gt;There is no need to register concrete types such as controllers or API controllers (unless you want to
/// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.&lt;/remarks&gt;
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your types here
// container.RegisterType&lt;iproductrepository productrepository ,&gt;();
container.RegisterType&lt;iurlmanager urlmanager ,&gt;();
}
}
}</pre>
<h4>3. Update the existing UrlController</h4>
<p>Let’s take a look at the new UrlController:</p>
<pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using PSC.Shorturl.Web.Business;
using PSC.Shorturl.Web.Models;
namespace PSC.Shorturl.Web.Controllers
{
public class UrlController : Controller
{
private IUrlManager _urlManager;
public UrlController(IUrlManager urlManager)
{
this._urlManager = urlManager;
}
[HttpGet]
public ActionResult Index()
{
Url url = new Url();
return View(url);
}
public async Task&lt;actionresult&gt; Index(Url url)
{
if (ModelState.IsValid)
{
url.ShortURL = await
this._urlManager.ShortenUrl(url.LongURL);
}
return View(url);
}
}
}</pre>
<p>As you see here, we’ve added a private field and a constructor. When the controller is selected, Unity knows that it should insert the UrlManager in the IUrlManager. We have no hard coupling on the implementation at the moment. The second Index method is now async, and returns a Task. This is because our final implementation of the UrlManager will call the database and check if the inserted URL actually exists. If this isn’t executed async, it will block the entire application until these actions are done; that’s something you don’t want. </p>
<p>Every new business manager you’re going to add, can be injected using Unity. </p>
<h3>Entity Framework</h3>
<p>As I’ve explained before, Entity Framework is a object relational mapping framework. You define a few classes with a few properties. These properties match the fields in the database. Before we can do anything with Entity Framework, we have to make set up the MySQL connection in the Web.config file. The code snippet below should be inserted in the configuration tag of Web.config: </p>
<pre class="brush: xml;"> &lt;connectionStrings&gt;
&lt;add name="Shorturl"
connectionString="Server=YourServer;Database=PSCShortUrl;Uid=youruser;Pwd=yourpassword;"
providerName="System.Data.SqlClient" /&gt;
&lt;/connectionStrings&gt;</pre>
<p>Make sure you put in the correct server, username and password.</p>
<p>Let’s add two entities (so two tables) for the URL shortener application to the Entities project. These are just plain classes. </p>
<h5>ShortUrl.cs</h5>
<pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PSC.Shorturl.Web.Entities
{
[Table("short_urls")]
public class ShortUrl
{
[Key]
[Column("id")]
public int Id { get; set; }
[Required]
[Column("long_url")]
[StringLength(1000)]
public string LongUrl { get; set; }
[Required]
[Column("segment")]
[StringLength(20)]
public string Segment { get; set; }
[Required]
[Column("added")]
public DateTime Added { get; set; }
[Required]
[Column("ip")]
[StringLength(50)]
public string Ip { get; set; }
[Required]
[Column("num_of_clicks")]
public int NumOfClicks { get; set; }
public Stat[] Stats { get; set; }
}
}</pre>
<h5>Stat.cs</h5>
<pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PSC.Shorturl.Web.Entities
{
[Table("stats")]
public class Stat
{
[Key]
[Column("id")]
public int Id { get; set; }
[Required]
[Column("click_date")]
public DateTime ClickDate { get; set; }
[Required]
[Column("ip")]
[StringLength(50)]
public string Ip { get; set; }
[Column("referer")]
[StringLength(500)]
public string Referer { get; set; }
public ShortUrl ShortUrl { get; set; }
}
}</pre>
<p>This is a very basic entity setup.</p>
<ul>
<li><strong>Table</strong> tells Entity Framework what the actual table name should be. </li>
<li><strong>Key</strong> tells Entity Framework that this property is the primary key. </li>
<li><strong>Column</strong> tells Entity Framework what the columns name is in the database. </li>
<li><strong>StringLength</strong> tells Entity Framework what the maximum string length of a property is (only if the type is “string”). </li>
</ul>
<p>This actually doesn’t do anything. We have to define a “data context”. The data context is the central piece in Entity Framework: it contains the relations between the different entities and contains the repositories. A repository is a collection of all records in a specific table mapped to a specific entity. Let’s add a ShortUrlContext to the Data project.</p>
<pre class="brush: csharp;">using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PSC.Shorturl.Web.Entities;
namespace PSC.Shorturl.Web.Data
{
public class ShorturlContext : DbContext
{
public ShorturlContext()
: base("name=Shorturl")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity&lt;stat&gt;()
.HasRequired(s =&gt; s.ShortUrl)
.WithMany(u =&gt; u.Stats)
.Map(m =&gt; m.MapKey("shortUrl_id"));
}
public virtual DbSet&lt;shorturl&gt; ShortUrls { get; set; }
public virtual DbSet&lt;stat&gt; Stats { get; set; }
}
}</pre>
<p>The string "name=Shorturl" in the constructor refers to the connection string in the Web.config file. The method OnModelCreating is where all the relations between the entities are configured. At the moment, there is only one relation, so not much going on there. The latest two properties are the repositories. Entity Framework knows that these should be filled with the correct entities.</p>
<p>Now that we have the entities and the database configured, it’s time to set up our first migration. A migration is a change to the database. When you add a migration, Entity Framework compares the database with your current entity configuration and creates a new migration. This new migration can then be pushed to the database. </p>
<p>First, we have to open the package manager console. </p>
<p><a href="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_PackageConsole.png"><img width="644" height="144" title="ShortUrl_PackageConsole" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto; display: block; padding-right: 0px; border-top-width: 0px" alt="ShortUrl_PackageConsole" src="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_PackageConsole_thumb.png" border="0"></a></p>
<p>Make sure the default project is “PSC.Shorturl.Web.Data”.</p>
<p><a href="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_PackageConsole_Data.png"><img width="644" height="144" title="ShortUrl_PackageConsole_Data" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto; display: block; padding-right: 0px; border-top-width: 0px" alt="ShortUrl_PackageConsole_Data" src="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_PackageConsole_Data_thumb.png" border="0"></a></p>
<p>Next, execute the command “enable-migrations”.</p>
<p><a href="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_PackageConsole_EnableMigration.png"><u></u><img width="644" height="144" title="ShortUrl_PackageConsole_EnableMigration" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto; display: block; padding-right: 0px; border-top-width: 0px" alt="ShortUrl_PackageConsole_EnableMigration" src="http://puresourcecode.com/dotnet/image.axd?picture=ShortUrl_PackageConsole_EnableMigration_thumb.png" border="0"></a></p>
<blockquote>
<p>If you have a Windows 10 Pro Insider Preview Build 11099, you can’t execute this command or other commands with Entity Framework. For updates see <a title="http://stackoverflow.com/questions/35060821/visual-studio-2015-entity-framework-and-enable-migrations-error" href="http://stackoverflow.com/questions/35060821/visual-studio-2015-entity-framework-and-enable-migrations-error">http://stackoverflow.com/questions/35060821/visual-studio-2015-entity-framework-and-enable-migrations-error</a></p>
</blockquote>
<p>A migrations configuration file will be added to the Data project. From now on, it will be possible to add new migrations. Execute the following command:</p>
<p><code>add-migration "InitialCreate"</code></p>
<p>This will add an initial migration to your Data project. When you execute the following command:</p>
<p><code>update-database</code></p>
<p>The migration will actually be written to the database. If everything went right, you’ll now see the created (but empty) tables in the newly created database.</p>
<p>Next step is the <a href="http://puresourcecode.com/dotnet/post/Creating-a-URL-shortener-using-ASPNET-WepAPI-and-MVC-implementing-the-business-layer" target="_blank">implementation on business layer</a>.</p>http://puresourcecode.com/dotnet/post/2016/01/28/Creating-a-URL-shortener-using-ASPNET-WepAPI-and-MVC
enrico.rossini.uk@live.comhttp://puresourcecode.com/dotnet/post/2016/01/28/Creating-a-URL-shortener-using-ASPNET-WepAPI-and-MVC#commenthttp://puresourcecode.com/dotnet/post.aspx?id=e9fbad2a-87a9-40c3-82eb-b41c1e6dd1afThu, 28 Jan 2016 12:28:00 -0800ASP.NETC#JavaScriptMVCWebAPIshorturlunityentity frameworkjsonormhenryhttp://puresourcecode.com/dotnet/pingback.axdhttp://puresourcecode.com/dotnet/post.aspx?id=e9fbad2a-87a9-40c3-82eb-b41c1e6dd1af1http://puresourcecode.com/dotnet/trackback.axd?id=e9fbad2a-87a9-40c3-82eb-b41c1e6dd1afhttp://puresourcecode.com/dotnet/post/2016/01/28/Creating-a-URL-shortener-using-ASPNET-WepAPI-and-MVC#commenthttp://puresourcecode.com/dotnet/syndication.axd?post=e9fbad2a-87a9-40c3-82eb-b41c1e6dd1af