Monday 28 September 2015

Building Web Apps With ASP.NET 5 MVC And Entity Framework 7

We will learn how to build web apps with ASP.NET 5 MVC and  Entity Framework 7

Everyone likes the technology that comes with an “open source” tag along with it. And yes! The new ASP.NET 5 is an open source project and cross platform framework.you are already feeling excited to learn ASP.NET 5 now! We have heard about ASP.NET 5 and its modularity like Node.js, thought why not give it a try. Believe guys! . ASP.NET 5 really stand up alongside many modern web application building frameworks with all the well-known concepts like Middleware, Services, etc. To know more about ASP.NET 5 and its architecture you can read ASP.NET official documentation.




What are we going to build?
In short we are going to build a simple CMS app to manage content of a fictional technical talk event. we named it “TechTalkers”. The app has an admin panel where an admin can manage viewable contents for the app users. we made a little user story for our “TechTalkers” application along with the technology stack that we are going to use.
  1. User Story:

    1.1 Admin
    Admin logout/login system
    Admin Panel
    Managing Speakers
    Managing Speech Topic associate with a speaker

    1.2 User
    A viewable website
    Speakers List
    Speaker Details
    Topic List
    Topic Details

  2. Technology Stack:

    2.1 ASP.NET 5

    MVC
    Razor View Engine
    Authentication & Authorization
    Identity

    2.2 Entity Framework
    ORM (object relational mapping) for managing application data with a local database.
    Entity framework code first
File, then New Project

We are going to use Visual Studio 2015. Configuring Mac and Linux for ASP.net 5 is easy as pie.

There you will find how to set things up for ASP.NET 5 on a MAC or LINUX and start developing using Visual Studio Code or whatever Editor you want.

Open up Visual Studio 2015. Go to File, then New Project and select ASP.NET Web Application. Give the project a name “TechTalkers” and hit ok. In the template screen, under ASP.NET 5 preview templates, select Web Application and hit OK. The template follows ASP.NET MVC pattern for structuring your web app. Also contains individual user account login/logout functionality built in it.


Project Structure

The project structure is very simple. You have your .cshtml (.cshtml extension is used for Razor Views. Razor enables you to write C# code inside your html file) files in the Views folder. All your data transfer objects/POCOs (plain old class object) resides in the Models folder. And the controllers resides in the Controllers folder. Controllers are used to route any incoming request to a specific business logic block in your app. Other than these, we have Services and Migrations folders. In Services folder we have files to configure third party services like Email and SMS. In Migrations folder we have snapshots of our database migraTion history. These get generated by Entity Frameworks.



Now, let’s run the project. Click on the play icon (select your favourite browser from browse with… option).



You will see a Registration and a Login page along with three other pages i.e. Home, About and Contact pages. User can register himself into the system using the Registration page and start using the application. Once you register yourself, all your credential info will be saved to a local database. Connection string of the local database can be found in the config.json file.
  1. {
  2. "AppSettings": {
  3. "SiteTitle": "TechTalkers.Web"
  4. },
  5. "Data": {
  6. "DefaultConnection": {
  7. "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=aspnet5-TechTalkers.Web-6bfb60b0-3080-4310-b46c-9dc1331c9bfa;Trusted_Connection=True;MultipleActiveResultSets=true"
  8. }
  9. }
  10. }
You can access the database from SQL Server Object Explorer window.



Our system is a little bit different from this architecture. In our system only one user can login/logout into and out of the system. He/She is of course an admin. We are going to explicitly create an admin user and place it right into our database. So, there is no need for a Registration page. Again there is no need for the About and Contact pages either.

Creating Object Models
Okay let’s get our hands dirty. We need to create two model classes that will be mapped to two different tables in our database using Entity Framework. One of the table is for holding info about speakers and next one is holding info about the speech topic associated with a speaker.

Now, right click on the Models folder and add two classes called Speaker and Topic. The model classes looks like the following code snippet:

Topic.cs

  1. public class Topic
  2. {
  3. public Guid TopicId { get; set; }
  4. public string Title { get; set; }
  5. }
Speaker.cs

  1. public class Topic
  2. {
  3. public Guid TopicId { get; set; }
  4. public string Title { get; set; }
  5. public Guid SpeakerId { get; set; }
  6. public Speaker Speaker { get; set; }
  7. }
The TopicId and SpeakerId will be mapped to the unique Identifier column/primary key to their respective tables. Every property defined in the classes will produce database column with appropriate column type except for the public Speaker Speaker { get; set; }. This property is used to navigate to the associated Speaker object of the Topic. That’s why it is called navigation property. The public Guid SpeakerId { get; set; } is used as a foreign key in the Speaker table.

Object Relational Mapping with Entity FrameworkWe have our models, now we have to map those to our local database tables. Entity framework going to help us achieving that. In the IdentityModels.cs class add two properties of type DbSet namely Speakers and Topics.

  1. public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
  2. {
  3. public DbSet<Speaker> Speakers { get; set; }
  4. public DbSet<Topic> Topics { get; set; }
  5. }
IdentityDbContext is used to create a bridge between your application context and the database so that you can communicate back and forth. DbSet of a generic type allows you to run Linq or Lamda queries on the respective database table.

We would have used the DbContext class instead of IdentityDbContext if we wanted to only generate our Topic and Speaker tables. But IdentityDbContext helps us in generating tables to store information such as user credentials, user roles etc. in addition with other database tables. Okay now rebuild the project. To have these two new tables in our database we have to run a migration command. Let’s do it. Open up your command prompt and change directory to your project folder and run the following command:

  1. dnvm use 1.0.0-beta5
  2. dnx . ef migration add AddedSpeakerTopicModels
  3. dnx . ef migration apply



Running those command will produce a new migration file under Migrations folder with a timestamp added to the front. It is the snapshot of the current database structure.



Next we will add controllers to interact with the Speaker and database Table.

Adding Speaker Controllers and ViewsRight click on the Controllers folder, then select add new item and add a MVC controller class; name it SpeakerController.



The controller class only contains an Index() method which returns an action result.

  1. public IActionResult Index()
  2. {
  3. return View();
  4. }
This action will be executed and return a view when a user go to the [application-url]/Speaker/Index or just [application-url]/Speaker URL. But since there is no View associated with this controller action we will see the following error:



Time to add the index view for the speaker controller's Index() action. Index view will show a table that shows all the Speakers added into the system and will also contain a link to add a new speaker in to the system. Add a new folder under Views folder named Speaker. Right click on the Speaker folder and select add new item and select MVC View Page. Give it the name Index since it is a view for the Index() action.



Copy and Paste the following mark-up
  1. @model IEnumerable<TechTalkers.Web.Models.Speaker>
  2. @{
  3. ViewBag.Title = "Speakers";
  4. }
  5. <h2>@ViewBag.Title</h2>
  6. <p>
  7. <a asp-action="Add">Add a new speaker</a>
  8. </p>
  9. <table class="table">
  10. <tr>
  11. <th>
  12. @Html.DisplayNameFor(model => model.Name)
  13. </th>
  14. <th>
  15. @Html.DisplayNameFor(model => model.Bio)
  16. </th>
  17. <th></th>
  18. </tr>
  19. @foreach (var item in Model)
  20. {
  21. <tr>
  22. <td>
  23. @Html.DisplayFor(modelItem => item.Name)
  24. </td>
  25. <td>
  26. @Html.DisplayFor(modelItem => item.Bio)
  27. </td>
  28. <td>
  29. <a asp-action="Detail" asp-route-speakerId="@item.SpeakerId">Detail</a> |
  30. <a asp-action="Edit" asp-route-speakerId="@item.SpeakerId">Edit</a> |
  31. <a asp-action="Delete" asp-route-speakerId="@item.SpeakerId">Delete</a>
  32. </td>
  33. </tr>
  34. }
  35. </table>
As you can see the view contains a table that shows all the Speakers available in the Speakers list. Also have links for viewing detail, editing and deleting a speaker. But we can't see it yet since we don't have any speakers available yet. To pass a list of speakers to this view we have to change our controller a bit. The modified controller looks like the following code snippet:

  1. public class SpeakerController : Controller
  2. {
  3. ApplicationDbContext _db;
  4. public SpeakerController(ApplicationDbContext db)
  5. {
  6. _db = db;
  7. }
  8. // GET: /<controller>/
  9. public IActionResult Index()
  10. {
  11. var speakers = _db.Speakers;
  12. return View(speakers);
  13. }
  14. }
So we instantiated an object of type ApplicationDbContext in the controller’s constructor. Now we can query on the database with Entity Framework using the context object _db. In Index() action we’ve queried and get all the speakers from the database in the speakers list and pass the list to our Index view. Now if you run the application and go to the same URL as before you will see this view below.



We’ve Add action attached to the add a speaker link. Let’s add two action controller for it.

  1. [HttpGet]
  2. public IActionResult Add()
  3. {
  4. return View();
  5. }
  6. [HttpPost]
  7. public IActionResult Add(Speaker speaker)
  8. {
  9. _db.Speakers.Add(speaker);
  10. _db.SaveChanges();
  11. return RedirectToAction("Index");
  12. }
We have two controller for Add. This is simply because when an admin request to [application-url]/Add URL he is requesting a ‘GET’ on our server which returns the Speaker adding form. Then if he fills all the info and click on add he will request a ‘POST’ on our server which contains the object built from that provided info. After getting the passed in speaker object we save that speaker to our database and redirect again to our Index view. The speaker adding view looks like the following code snippet:

  1. @model TechTalkers.Web.Models.Speaker
  2. @{
  3. ViewBag.Title = "Add a Speaker";
  4. }
  5. <h2>@ViewBag.Title</h2>
  6. <div>
  7. <form asp-controller="Speaker" asp-action="Add" method="post">
  8. <div class="form-group">
  9. <label asp-for="Name"></label>
  10. <input asp-for="Name" class="form-control" placeholder="name" />
  11. </div>
  12. <div class="form-group">
  13. <label asp-for="Bio"></label>
  14. <textarea asp-for="Bio" class="form-control" rows=5 placeholder="bio"></textarea>
  15. </div>
  16. <input type="submit" class="btn btn-default" value="Add" />
  17. </form>
  18. </div>
Running the project and adding a user shows the added speaker like this in the Index view. Previously, I’ve added three speakers so the list shows four speakers.



Creating Detail view and its controller is also easy. From the Index view we pass the speakerId to our detail view.

  1. <a asp-action="Detail" asp-route-speakerId="@item.SpeakerId">Detail</a>
That’s why we need an http ‘GET’ controller that takes a speakerId as an input parameter. All we have to do then is to search the speaker associated with the speakerId and pass that speaker to our Detail view. The controller looks like the following code snippet:

  1. [HttpGet]
  2. public IActionResult Detail(Guid speakerId)
  3. {
  4. var id = RouteData.Values["speakerId"];
  5. Speaker speaker = _db.Speakers.FirstOrDefault(s => s.SpeakerId == speakerId);
  6. return View(speaker);
  7. }
This is the view

  1. @model TechTalkers.Web.Models.Speaker
  2. @{
  3. ViewBag.Title = "Details";
  4. }
  5. <h2>@ViewBag.Title</h2>
  6. <div>
  7. <dl class="dl-horizontal">
  8. <dt>@Html.DisplayNameFor(model => model.Name)</dt>
  9. <dd>@Html.DisplayFor(model => model.Name)</dd>
  10. <dt>@Html.DisplayNameFor(model => model.Bio)</dt>
  11. <dd>@Html.DisplayFor(model => model.Bio)</dd>
  12. </dl>
  13. </div>
Here is what it looks like,

Like the add view we’ve two controllers for the Edit view. One of these exactly looks like the Detail controller because we have to pass the selected speaker to the Edit view to have the previous values for the input field. The second controller is quite similar to the second Add controller except that we update the speaker instead of adding it to the database. Here goes the two controllers.

  1. [HttpGet]
  2. public IActionResult Edit(Guid speakerId)
  3. {
  4. Speaker speaker = _db.Speakers.FirstOrDefault(s => s.SpeakerId == speakerId);
  5. return View(speaker);
  6. }
  7. [HttpPost]
  8. public IActionResult Edit(Speaker speaker)
  9. {
  10. _db.Speakers.Update(speaker);
  11. _db.SaveChanges();
  12. return RedirectToAction("Index");
  13. }
The Edit view looks like the following screenshot:




  1. @model TechTalkers.Web.Models.Speaker
  2. @{
  3. ViewBag.Title = "Edit Speaker";
  4. }
  5. <h2>@ViewBag.Title</h2>
  6. <div>
  7. <form asp-controller="Speaker" asp-action="Edit" method="post" asp-route-speakerId="@Model.SpeakerId">
  8. <div class="form-group">
  9. <label asp-for="Name"></label>
  10. <input asp-for="Name" class="form-control" />
  11. </div>
  12. <div class="form-group">
  13. <label asp-for="Bio"></label>
  14. <textarea asp-for="Bio" rows=3 class="form-control"></textarea>
  15. </div>
  16. <input type="submit" class="btn btn-default" value="Edit" />
  17. </form>
  18. </div>
Last of all the Delete controller. First we have to select the speaker with the passed in speakerId and show detail about it in the delete view. In delete view we have to have a delete button which will ultimately delete the speaker. The controllers are given below:

  1. [HttpGet]
  2. public IActionResult Delete(Guid speakerId)
  3. {
  4. Speaker speaker = _db.Speakers.FirstOrDefault(s => s.SpeakerId == speakerId);
  5. return View(speaker);
  6. }
  7. public IActionResult DeleteConfirmed(Guid speakerId)
  8. {
  9. Speaker speaker = _db.Speakers.FirstOrDefault(s => s.SpeakerId == speakerId);
  10. _db.Speakers.Remove(speaker);
  11. _db.SaveChanges();
  12. return RedirectToAction("Index");
  13. }
Here's the code for view:

  1. @model TechTalkers.Web.Models.Speaker
  2. @{
  3. ViewBag.Title = "Delete";
  4. }
  5. <h2>@ViewBag.Title</h2>
  6. <div>
  7. <dl class="dl-horizontal">
  8. <dt>@Html.DisplayNameFor(model => model.Name)</dt>
  9. <dd>@Html.DisplayFor(model => model.Name)</dd>
  10. <dt>@Html.DisplayNameFor(model => model.Bio)</dt>
  11. <dd>@Html.DisplayFor(model => model.Bio)</dd>
  12. </dl>
  13. <form asp-controller="Speaker" asp-action="DeleteConfirmed" asp-route-speakerId="@Model.SpeakerId">
  14. <input type="submit" class="btn btn-default" value="Delete" />
  15. </form>
  16. </div>
Let’s give it a spin.



Adding Topic Controllers and Views Most of the work is almost same as creating the Speaker controllers and views. Additional works requires us to put a dropdown list of available speakers for selecting one associated with a topic. Let’s do it.

As before create a controller and name it TopicController. Create an ApplicationDbContext instance in the constructor. Create the Index() controller as before except now pass the list of topics to the view. Don’t forget to include the navigational property we talked about.

  1. public IActionResult Index()
  2. {
  3. var topics = _db.Topics.Include(s=>s.Speaker);
  4. return View(topics);
  5. }
Nothing new in the view. Just copy and paste the markup given below,

  1. @model IEnumerable<TechTalkers.Web.Models.Topic>
  2. @{
  3. ViewBag.Title = "Topics";
  4. }
  5. <h2>@ViewBag.Title</h2>
  6. <p>
  7. <a asp-action="Add">Add a new topic</a>
  8. </p>
  9. <table class="table">
  10. <tr>
  11. <th>
  12. @Html.DisplayNameFor(model => model.Title)
  13. </th>
  14. <th>
  15. @Html.DisplayNameFor(model => model.Speaker)
  16. </th>
  17. <th></th>
  18. </tr>
  19. @foreach (var item in Model)
  20. {
  21. <tr>
  22. <td>
  23. @Html.DisplayFor(modelItem => item.Title)
  24. </td>
  25. <td>
  26. @Html.DisplayFor(modelItem => item.Speaker.Name)
  27. </td>
  28. <td>
  29. <a asp-action="Detail" asp-route-topicId="@item.TopicId">Detail</a> |
  30. <a asp-action="Edit" asp-route-topicId="@item.TopicId">Edit</a> |
  31. <a asp-action="Delete" asp-route-topicId="@item.TopicId">Delete</a>
  32. </td>
  33. </tr>
  34. }
  35. </table>
Slight change in Add controller, we should send the list of speakers to the view so that an admin can select one from it while creating a topic. So we pass the speakers list in a ViewBag object.

  1. [HttpGet]
  2. public IActionResult Add()
  3. {
  4. Speakers = GetAllSpeakers();
  5. ViewBag.Speakers = Speakers;
  6. return View();
  7. }
  8. private IEnumerable<SelectListItem> GetAllSpeakers()
  9. {
  10. return _db.Speakers.ToList().Select(speaker => new SelectListItem
  11. {
  12. Text = speaker.Name,
  13. Value = speaker.SpeakerId.ToString(),
  14. });
  15. }
The add topic view looks like this. We pass the speakers list available in the ViewBag object to the html select control.

  1. @model TechTalkers.Web.Models.Topic
  2. @{
  3. ViewBag.Title = "Add a Topic";
  4. }
  5. <h2>@ViewBag.Title</h2>
  6. <div>
  7. <form asp-controller="Topic" asp-action="Add" method="post">
  8. <div class="form-group">
  9. <label asp-for="Title"></label>
  10. <input asp-for="Title" class="form-control" placeholder="title" />
  11. </div>
  12. <div class="form-group">
  13. <select asp-for="SpeakerId" asp-items="@ViewBag.Speakers" class="form-control"></select>
  14. </div>
  15. <input type="submit" class="btn btn-default" value="Add"/>
  16. </form>
  17. </div>
Finally for the postback Add controller we have this,

  1. [HttpPost]
  2. public IActionResult Add(Topic topic)
  3. {
  4. _db.Topics.Add(topic);
  5. _db.SaveChanges();
  6. return RedirectToAction("Index");
  7. }
Here goes the detail view and its associated controller

  1. @model TechTalkers.Web.Models.Topic
  2. @{
  3. ViewBag.Title = "Details";
  4. }
  5. <h2>@ViewBag.Title</h2>
  6. <div>
  7. <dl class="dl-horizontal">
  8. <dt>@Html.DisplayNameFor(model => model.Title)</dt>
  9. <dd>@Html.DisplayFor(model => model.Title)</dd>
  10. <dt>@Html.DisplayNameFor(model => model.Speaker)</dt>
  11. <dd>@Html.DisplayFor(model => model.Speaker.Name)</dd>
  12. </dl>
  13. </div>
Topic Detail controller

  1. [HttpGet]
  2. public IActionResult Detail(Guid topicId)
  3. {
  4. Topic topic = _db.Topics.Include(s=>s.Speaker).FirstOrDefault(t => t.TopicId == topicId);
  5. return View(topic);
  6. }
Topic Edit view and its controller are below:

  1. @model TechTalkers.Web.Models.Topic
  2. @{
  3. ViewBag.Title = "Edit Topic";
  4. }
  5. <h2>@ViewBag.Title</h2>
  6. <div>
  7. <form asp-controller="Topic" asp-action="Edit" method="post" asp-route-topicId="@Model.TopicId">
  8. <div class="form-group">
  9. <label asp-for="Title"></label>
  10. <input asp-for="Title" class="form-control" />
  11. </div>
  12. <div class="form-group">
  13. <label asp-for="Speaker"></label>
  14. <select asp-for="SpeakerId" asp-items="@ViewBag.Speakers" class="form-control"></select>
  15. </div>
  16. <input type="submit" class="btn btn-default" value="Edit" />
  17. </form>
  18. </div>
Again in Topic Edit controller we passed the speakers list in a ViewBag so that the select control can get populated. Second controller is same as the second Edit view of the Speaker.

  1. [HttpGet]
  2. public IActionResult Edit(Guid topicId)
  3. {
  4. Speakers = GetAllSpeakers();
  5. ViewBag.Speakers = Speakers;
  6. Topic topic = _db.Topics.Include(s => s.Speaker).FirstOrDefault(t => t.TopicId == topicId);
  7. return View(topic);
  8. }
  9. [HttpPost]
  10. public IActionResult Edit(Topic topic)
  11. {
  12. _db.Topics.Update(topic);
  13. _db.SaveChanges();
  14. return RedirectToAction("Index");
  15. }
The Delete View and Controller is given below

  1. @model TechTalkers.Web.Models.Topic
  2. @{
  3. ViewBag.Title = "Delete";
  4. }
  5. <h2>@ViewBag.Title</h2>
  6. <div>
  7. <dl class="dl-horizontal">
  8. <dt>@Html.DisplayNameFor(model => model.Title)</dt>
  9. <dd>@Html.DisplayFor(model => model.Title)</dd>
  10. <dt>@Html.DisplayNameFor(model => model.Speaker)</dt>
  11. <dd>@Html.DisplayFor(model => model.Speaker.Name)</dd>
  12. </dl>
  13. <form asp-controller="Topic" asp-action="DeleteConfirmed" asp-route-topicId="@Model.TopicId">
  14. <input type="submit" class="btn btn-default" value="Delete" />
  15. </form>
  16. </div>
Last of all the Delete controllers. One for ‘GET’ and one for ‘POST’ request.

  1. [HttpGet]
  2. public IActionResult Delete(Guid topicId)
  3. {
  4. Topic topic = _db.Topics.Include(s => s.Speaker).FirstOrDefault(t => t.TopicId == topicId);
  5. return View(topic);
  6. }
  7. public IActionResult DeleteConfirmed(Guid topicId)
  8. {
  9. Topic topic = _db.Topics.FirstOrDefault(t => t.TopicId == topicId);
  10. _db.Topics.Remove(topic);
  11. _db.SaveChanges();
  12. return RedirectToAction("Index");
  13. }
Let's have a look if we did any mistakes.



Everything looks good.

Adding Admin AuthenticationAs we have already said our system will consist of one single user who is ultimately an admin. Only an admin can add/remove/edit Topics and Speakers. So, there is no need for a registration view for outside users. You can remove most of the AccountController code but I’m going to comment out for now. Commenting out code is good rather than deleting. You may need that block in future.

  1. public IActionResult Register() { ... }
  2. public async Task<IActionResult> Register(RegisterViewModel model) { ... }
We have controller for External [registration via google/facebook/Microsoft/twitter] user registration. Don’t worry about them because if you don’t have your app registered to those service you won’t get access to the external registration/login services. Means that commenting out those controllers or keeping them don’t matter anyways.

We created a class which is responsible for initializing the database with a user in admin role. Here is what it looks like

  1. public class DatabaseInitializer : IDatabaseInitializer
  2. {
  3. private readonly UserManager<ApplicationUser> _userManager;
  4. private readonly RoleManager<IdentityRole> _roleManager;
  5. public DatabaseInitializer(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager)
  6. {
  7. _userManager = userManager;
  8. _roleManager = roleManager;
  9. }
  10. public async Task CreateUserAndRoleAsync()
  11. {
  12. var user = await _userManager.FindByEmailAsync("fiyazhasan@gmail.com");
  13. if (user == null)
  14. {
  15. user = new ApplicationUser {
  16. UserName = "fiyazhasan@gmail.com",
  17. Email = "fiyazhasan@gmail.com"
  18. };
  19. await _userManager.CreateAsync(user, "@Fizz1234");
  20. }
  21. var role = await _roleManager.FindByNameAsync("admin");
  22. if (role == null) {
  23. role = new IdentityRole {
  24. Name = "admin"
  25. };
  26. await _roleManager.CreateAsync(role);
  27. }
  28. await _userManager.AddToRoleAsync(user, "admin");
  29. }
  30. }
  31. public interface IDatabaseInitializer
  32. {
  33. Task CreateUserAndRoleAsync();
  34. }
Implementing an interface is just for the sake of dependency injection. You don’t have to do that if you don’t want to. In DatabaseInitializer we have to properties which helps us to talk to the Identity module. To create a new user we use the UserManager and to manage role for them we use RoleManager classes. UserManager is capable of working with the ApplicationUser type which is just an implementation of IdentityUser. This class can be found in the IdentityModels class.

  1. public class ApplicationUser : IdentityUser
  2. {
  3. }
  4. public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
  5. {
  6. public DbSet<Speaker> Speakers { get; set; }
  7. public DbSet<Topic> Topics { get; set; }
  8. protected override void OnModelCreating(ModelBuilder builder)
  9. {
  10. base.OnModelCreating(builder);
  11. // Customize the ASP.NET Identity model and override the defaults if needed.
  12. // For example, you can rename the ASP.NET Identity table names and more.
  13. // Add your customizations after calling base.OnModelCreating(builder);
  14. }
  15. }
As you can see the ApplicationUser class is empty. You can add additional properties here as a required field while registration else just throw it away and simply use IdentityUser with UserManager which I did in the case of RoleManager(used IdentityRole in RoleManager). Rest of the code is self-explanatory. All I did is create a user and assign a role of admin.

Now we have to inject this initializer class in to the ConfigureServices method found in the startup class. Now to run the initializer when the app runs we call the CreateUserAndRoleAsync() method found in the same class where the ConfigureServices() resides. Here is the final look of the startup class.

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. // Add Entity Framework services to the services container.
  4. services.AddEntityFramework()
  5. .AddSqlServer()
  6. .AddDbContext<ApplicationDbContext>(options =>
  7. options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
  8. // Add Identity services to the services container.
  9. services.AddIdentity<ApplicationUser, IdentityRole>()
  10. .AddEntityFrameworkStores<ApplicationDbContext>()
  11. .AddDefaultTokenProviders();
  12. // Configure the options for the authentication middleware.
  13. // You can add options for Google, Twitter and other middleware as shown below.
  14. // For more information see http://go.microsoft.com/fwlink/?LinkID=532715
  15. services.Configure<FacebookAuthenticationOptions>(options =>
  16. {
  17. options.AppId = Configuration["Authentication:Facebook:AppId"];
  18. options.AppSecret = Configuration["Authentication:Facebook:AppSecret"];
  19. });
  20. services.Configure<MicrosoftAccountAuthenticationOptions>(options =>
  21. {
  22. options.ClientId = Configuration["Authentication:MicrosoftAccount:ClientId"];
  23. options.ClientSecret = Configuration["Authentication:MicrosoftAccount:ClientSecret"];
  24. });
  25. // Add MVC services to the services container.
  26. services.AddMvc();
  27. // Uncomment the following line to add Web API services which makes it easier to port Web API 2 controllers.
  28. // You will also need to add the Microsoft.AspNet.Mvc.WebApiCompatShim package to the 'dependencies' section of project.json.
  29. // services.AddWebApiConventions();
  30. // Register application services.
  31. services.AddTransient<IEmailSender, AuthMessageSender>();
  32. services.AddTransient<ISmsSender, AuthMessageSender>();
  33. services.AddTransient<IDatabaseInitializer,DatabaseInitializer>();
  34. }
  35. // Configure is called after ConfigureServices is called.
  36. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IDatabaseInitializer databaseInitializer)
  37. {
  38. loggerFactory.MinimumLevel = LogLevel.Information;
  39. loggerFactory.AddConsole();
  40. // Configure the HTTP request pipeline.
  41. // Add the following to the request pipeline only in development environment.
  42. if (env.IsDevelopment())
  43. {
  44. app.UseBrowserLink();
  45. app.UseErrorPage(ErrorPageOptions.ShowAll);
  46. app.UseDatabaseErrorPage(DatabaseErrorPageOptions.ShowAll);
  47. }
  48. else
  49. {
  50. // Add Error handling middleware which catches all application specific errors and
  51. // sends the request to the following path or controller action.
  52. app.UseErrorHandler("/Home/Error");
  53. }
  54. // Add static files to the request pipeline.
  55. app.UseStaticFiles();
  56. // Add cookie-based authentication to the request pipeline.
  57. app.UseIdentity();
  58. // Add authentication middleware to the request pipeline. You can configure options such as Id and Secret in the ConfigureServices method.
  59. // For more information see http://go.microsoft.com/fwlink/?LinkID=532715
  60. // app.UseFacebookAuthentication();
  61. // app.UseGoogleAuthentication();
  62. // app.UseMicrosoftAccountAuthentication();
  63. // app.UseTwitterAuthentication();
  64. // Add MVC to the request pipeline.
  65. app.UseMvc(routes =>
  66. {
  67. routes.MapRoute(
  68. name: "default",
  69. template: "{controller=Home}/{action=Index}/{id?}");
  70. // Uncomment the following line to add a route for porting Web API 2 controllers.
  71. // routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
  72. });
  73. databaseInitializer.CreateUserAndRoleAsync();
  74. }
Restricting outside users from adding, editing and deleting Speakers and TopicsThis step is super simple, all we have to do is to decorate our Add, Edit and Delete controller with the [Authorize(Roles = "admin")]. Means that we only want to give the admin access to the controllers. Here is what looks like after adding the attribute to the speaker’s Add, Edit and Delete controllers. Please do the same for Topic controllers.

  1. public class SpeakerController : Controller
  2. {
  3. readonly ApplicationDbContext _db;
  4. public SpeakerController(ApplicationDbContext db)
  5. {
  6. _db = db;
  7. }
  8. // GET: /<controller>/
  9. public IActionResult Index()
  10. {
  11. var speakers = _db.Speakers;
  12. return View(speakers);
  13. }
  14. [HttpGet]
  15. [Authorize(Roles = "admin")]
  16. public IActionResult Add()
  17. {
  18. return View();
  19. }
  20. [HttpPost]
  21. [Authorize(Roles = "admin")]
  22. public IActionResult Add(Speaker speaker)
  23. {
  24. _db.Speakers.Add(speaker);
  25. _db.SaveChanges();
  26. return RedirectToAction("Index");
  27. }
  28. [HttpGet]
  29. [Authorize(Roles = "admin")]
  30. public IActionResult Detail(Guid speakerId)
  31. {
  32. Speaker speaker = _db.Speakers.FirstOrDefault(s => s.SpeakerId == speakerId);
  33. return View(speaker);
  34. }
  35. [HttpGet]
  36. [Authorize(Roles = "admin")]
  37. public IActionResult Edit(Guid speakerId)
  38. {
  39. Speaker speaker = _db.Speakers.FirstOrDefault(s => s.SpeakerId == speakerId);
  40. return View(speaker);
  41. }
  42. [HttpPost]
  43. [Authorize(Roles = "admin")]
  44. public IActionResult Edit(Speaker speaker)
  45. {
  46. _db.Speakers.Update(speaker);
  47. _db.SaveChanges();
  48. return RedirectToAction("Index");
  49. }
  50. [HttpGet]
  51. [Authorize(Roles = "admin")]
  52. public IActionResult Delete(Guid speakerId)
  53. {
  54. Speaker speaker = _db.Speakers.FirstOrDefault(s => s.SpeakerId == speakerId);
  55. return View(speaker);
  56. }
  57. [Authorize(Roles = "admin")]
  58. public IActionResult DeleteConfirmed(Guid speakerId)
  59. {
  60. Speaker speaker = _db.Speakers.FirstOrDefault(s => s.SpeakerId == speakerId);
  61. _db.Speakers.Remove(speaker);
  62. _db.SaveChanges();
  63. return RedirectToAction("Index");
  64. }
  65. }
Now, if you try to add/edit/delete a speaker or topic as an outside user, you will be taken to the login screen. If you logged in using the admin credentials then you can add/edit/delete a speaker or topic.

Time to remove the Registration and Login links from the Layout page. Go to Views, Shared, then_LoginPartial and comment out these lines.

  1. else
  2. {
  3. <ul class="nav navbar-nav navbar-right">
  4. <li><a asp-action="Register" asp-controller="Account">Register</a></li>
  5. <li><a asp-action="Login" asp-controller="Account">Log in</a></li>
  6. </ul>
  7. }
The line is responsible for showing a register and login links to outside users. Of course we don't need it. Admin can simply login by going to this lik - [application-url]/Account/Login.

Before leaving just add the Speaker and Topic view link in the _Layout view. Replace the About and Contact Link with these two,

  1. <li><a asp-controller="Topic" asp-action="Index">Topic</a></li>
  2. <li><a asp-controller="Speaker" asp-action="Index">Speaker</a></li>   

Friday 25 September 2015

Extra Support Can Help Improve Attendance and Strengthen a Student’s Academic Achievement


Attendance is crucial to positive long term outcomes for students and numerous studies have shown that 6th graders who are chronically absent have lower high school graduation rates. What does life look like for high school dropouts? They’re three times more likely than college graduates to be unemployed and eight times more likely than high school graduates to be in jail.
It’s probably obvious that students need to be present and engaged at school to learn, but regular attendance offers several additional benefits:
  1. Exposure to Language: School exposes children to language-rich environments they may not have at home.
  2. Positive peer relationships: When students are at school they are exposed to peer groups and learn important interpersonal and communication skills.
  3. Lifelong skills: Good attendance builds habits, essential for success in school and life.
  4. Engagement: Students have the opportunity to participate in non-academic activities such as sports, clubs, student leadership activities, music, etc. Positive classroom and school climate: When all students are present, they have the ability to impact classroom instruction and affect school climate.
So how can City Year corps members support students come to school every day to reap the benefits that school offers? In 2004, a report by the Northwest Regional Educational Laboratory found four key strategies for increasing student attendance. These strategies include schools creating sound attendance policies, providing early interventions especially to elementary aged students, targeted interventions for students with chronic attendance problems and increasing the engagement of students and families at school.  City Year has developed our attendance support model for schools and students based on these strategies, and across the country you will find teams of corps members working hard to put them into action.
Student Engagement
Creating a school culture of high attendance, where attendance is recognized and celebrated, is one strategy to engage students in thinking more critically about their individual and school-wide attendance. Corps members help to develop school-wide attendance initiatives that provide recognition for improved and excellent attendance. This may include data walls showcasing school, class and individual attendance, parties and special events or incentives, such as dances and special assemblies, to celebrate performance. Corps members also provide engagement and community building opportunities throughout the school day and afterschool- all of which help students feel supported, engaged and excited to come to school.
Parent Engagement
Parents are a critical component to student success at school. Each day corps members make phone calls home to students who are absent from school to encourage that student to come to school that day, and to come to school the next day as well.  Often, corps members are speaking with parents and guardians who not only help us learn more about the reasons behind student absences but also use the time to work together to build strategies that will help their student attend school regularly.
Targeted Interventions
For some students, coming to school isn’t as easy as setting an alarm and getting up in time to catch the bus. Many students, particularly those living in poverty, face systemic barriers that make going to school challenging. These include poor transportation options (including lack of safe walking options due to neighborhood violence), feeling unsafe at school, or responsibilities outside of school (jobs or caretaking for family members). Often times students struggling with these issues are chronically absent. Corps members meet weekly with those students to set attendance goals, troubleshoot potential challenges to coming to school, and problem solve for any issues they are facing.  Because we know that students are more likely to remain and achieve in schools where people care about them* this intervention provides an opportunity for students to build a support system of adults and peers at school while helping them understand the importance of school to their lives, and develop key lifelong skills like responsible decision making, problem solving, goal setting and perseverance.

Tally.ERP 9 - First Impressions

The new financial year has started and Tally has launched its ERP offering just in time. The new product launch was reason enough for increased customer interest and hence there were no special offers this March for product promotion.

My first impression of Tally.ERP has been positive. Users and administrators are going to like the Control Center and Support Center features. The flagship feature of Tally's ERP is the remote access feature, and businesses will realise the benefit of this feature down the line.

There are a few bottlenecks, though. Like the user getting the Unlock Key in mail after a long delay. With ERP, Tally has introduced a lot of new terminology, especially a lot of 'ID's, e.g your .NET ID, Site ID, Account ID and Account Admin ID. It will take some getting used to for normal users.

Quite a few existing Tally customizations have stopped working in ERP, and even after TCP conversion using the TallyAdmin tool, the TCP either gives load-time error or functional error.

We have migrated our existing TCPs to the ERP platform free of cost for most customers. TDL programmers will have a hectic schedule ahead, with fresh orders as well as migration of existing TDLs to the new platform. Moreover, they also have to get used to the powerful syntax and features of the enhanced TDL language.

A common concern among users interested in Tally customization is what will happen to the customized features when Tally brings a new release or version.

My answer is that in 90% of the new releases or versions, TDLs will run without needing any changes. In case of a major version release, there are chances that TDLs may not work correctly, as in the case of 7.2 to 9 conversion and 9.2 to 9.ERP conversion. However for all other releases in between, TDLs have continued to work smoothly.

Even when customized files do not work in the new version, it requires mostly a few adjustments as per the new language features / capabilities. For this, the user should not worry too much as the charges will be extremely nominal. And so far, we have done the TCP conversion free of cost for our users.

The road ahead for Tally.ERP is extremely bright and you can keep high expectations from the product in the coming months and years.

Company News: New customers added in Ahmedabad & Mathura. We have also started Tally product sales in Delhi (on-site installation service available, support through remote access)

Management Information System (MIS)

MIS is:
  • Integrated man-machine system
  • For providing information
  • To support operations, management, analysis and decision making functions
  • In an organization
MIS uses:
  • Computer hardware and software
  • Manual processes
  • Models for analysis, planning, control and decision making
  • Database
MIS can also be defined as a planned system of the collecting, processing, storing and disseminating information needed to carry out the functions of management.
Data and Information
  • Terms "data" and "information" are used normally in a loose manner and interchangeably.
  • Also same set of figures can be seen as data or information some times. Thus, data becomes information seen within a context.
  • So, information is defined as data that is meaningful or useful to it's user.
  • Data, therefore, can be considered as raw material to produce information.
MIS Structure
There are primarily four building blocks for the structure of complete MIS. They are:
  • Organizational functions and cross-functional processes.
  • Management activities at different hierarchical levels.
  • Decision support.
  • operating elements.
Organizational functions
  • MIS structure has to be designed to satisfy the requirements of various organizational functions.
  • In addition, there will be many cross functional processes going on in an organization.
  • Each of these require information for their various levels of hierarchical activities which are normally known as transaction processing (clerical/worker level), operational control (junior/middle management level), managerial control (senior management level) and strategic planning (top management level).
  • These organizational functions, as we know, are: marketing and sales, supply chain (materials), manufacturing, logistics, human resources, finance and accounting, information technology and top management. Each of these functions also interact with each other in cross functional processes in the project phases and also during stabilized business phases.
Hierachical Management Activities
  • MIS structure has to be designed to satisfy various hierarchical information requirements.
  • There are four levels of hierarchy: strategic planning (top management), management control and tactical planning (senior management), operations planning and control (middle and junior management), transaction processing (clerical staff and workers).
  • At each level of management, the nature of information in terms of details, conciseness, frequency, interpretations, decision supporting/decision giving capabilities etc is different and MIS structure should support it.
Decision Making
  • Nature of decisions vary for each hierarchical level in each management function.
  • Broadly, these decisions can be classified in two ways as: structured (programmable) decisions and unstructured (non programmable) decisions.
  • MIS requirements for structured programmable decisions are clear, unambiguous and decision making logic can be formulated. These are normally related to the requirements of transaction processing and operation control levels in various functions of the organization.
  • MIS requirements for unstructured non programmable decisions are ambiguous and often frequently changeable,. The decision making is not amenable for pre-established procedures or logic. These are normally related to the requirements of strategic planning and some times, for management control levels. Information requirements are not fully known in advance information/data retrieval is done through adhoc enquiries.
  • MIS structure should address to the needs of both the types of decision making mentioned earlier.
Operationg elements of MIS
  • MIS that has to support the requirement of various types of decision making at different hierarchical levels in various functions of an organizations, finally has it's operating elements on which the entire structure is created.
  • There are three operating elements: physical components, processing functions and outputs for the users of information.
  • Physical components are: hardware, software, database, algorithms (procedures or logic) and the people/experts in information technology function.
  • Processing functions include: transaction processing, data base maintenance, reports production, enquiry processing and interactive support applications.
  • Types of outputs are: transactional types or action oriented, informational and decision support types.
  • The operating elements of MIS structure should be designed keeping these (physical components, processing functions and types of information outputs) in mind.
Finally, the four building blocks of MIS structure i.e. organizational functions, management hierarchical activities, types of decision making and operating elements should be synthesized into each other to make a seamless, integrated and contingency based MIS structure.

Explained: What is the Internet of Things?

 

What is the Internet of Things, exactly? It is an ambiguous term, but it is fast becoming a tangible technology that can be applied in data centers to collect information on just about anything that IT wants to control.
The Internet of Things (IoT) is essentially a system of machines or objects outfitted with data-collecting technologies so that those objects can communicate with one another. The machine-to-machine (M2M) data that is generated has a wide range of uses, but is commonly seen as a way to determine the health and status of things -- inanimate or living.
Internet of Things
IT administrators can use the IoT for anything in their physical environment that they want information about. In fact, they already do.
In one case, IoT is being used to stymie deforestation in the Amazon rainforest. A Brazilian location-services company called Cargo Tracck places M2M sensors from security company Gemalto in trees in protected areas. When a tree is cut or moved, law enforcement receives a message with its GPS location, allowing authorities to track down the illegally removed tree.
One analyst explained the IoT using the iPhone as an analogy. Disconnected third-party applications that are hosted in the cloud can be connected, and users can access all sorts of data from the device, according to Sam Lucero, senior principal analyst, M2M and Internet of Things, at IHS Electronics & Media in Tempe, Ariz.

How the Internet of Things works

While some consider IoT to be M2M communication over a closed network, that model is really just an intranet of things, Lucero said.
With an Intranet of Things, apps are deployed for a specific purpose and don’t interact outside of that network. The true IoT is where different applications are deployed for specific reasons and the data collected from the machines and objects being monitored are made available to third-party applications. The expectation is that true IoT will provide more value than what can be derived from secluded islands of information, Lucero said.
For the IoT to work in data centers, platforms from competing vendors need to be able to communicate with one another. This requires standard APIs that all vendors and equipment can plug into, for both the systems interfaces as well as various devices, said Mike Sapien, a principal analyst with Ovum.
IBM proposed in February that its IoT protocol, called Message Queuing Telemetry Transport (MQTT), be used as the open standard. This would help multiple vendors participate in the IoT.
“[System integrators] like HP, IBM and others are starting to open up their systems to be less restrictive, just as telecom operators are allowing different networks—not just their own—to be part of the IoT ecosystem,” Sapien said. “But this has taken many years to happen.”
Meanwhile, a number of platforms serve as the plumbing to connect systems from different vendors so that they can communicate and be managed. One such platform is Xively Cloud Services, which is LogMeIn Inc.’s public IoT Platform as a Service. It allows IT to design, prototype and put into production any Internet-connected device.
For example, companies that have to monitor energy use might use closed, vendor-specific systems. They can use something like Xively as a secondary system to monitor heating and cooling and control energy use across multiple locations.
Over the long term, one consequence of the Internet of Things for the enterprise data center could be a large volume of incoming data coming that requires significant infrastructure upgrades, particularly for data processing and storage

Wednesday 23 September 2015

What is a hacker? and Hacker Hierarchy

 What is a hacker?
A hacker is someone who likes to tinker with electronics or computer systems. Hackers like to explore and learn how computer systems work, finding ways to make them do what they do better, or do things they weren’t intended to do. There are two types of hackers:

White Hat – These are considered the good guys. White hat hackers don’t use their skills for illegal purposes. They usually become Computer Security experts and help protect people from the Black Hats.

Black Hat – These are considered the bad guys. Black hat hackers usually use their skills maliciously for personal gain. They are the people that hack banks, steal credit cards, and deface websites.
These two terms came from the old western movies where the good guys wore white hats and the bad guys wore black hats.

Now if you’re thinking, “Oh boy! Being a black hat sounds awesome!”, Then I have a question for you. Does it sound cool to live in a cell the size of your bathroom and be someone’s butt buddy for many years? That’s what I thought.

                                                            Hacker Hierarchy
Script kiddies – These are the wannabe hackers. They are looked down upon in the hacker community because they are the people that make hackers look bad. Script kiddies usually have no hacking skills and use the tools developed by other hackers without any knowledge of what’s happening behind the scenes.

Intermediate hackers – These people usually know about computers, networks, and have enough programming knowledge to understand relatively what a script might do, but like the script kiddies they use pre-developed well-known exploits (- a piece of code that takes advantage of a bug or vulnerability in a piece of software that allows you to take control of a computer system) to carry out attacks

Elite Hackers – These are the skilled hackers. They are the ones that write the many hacker tools and exploits out there. They can break into systems and hide their tracks or make it look like someone else did it. You should strive to eventually reach this level.

Note:so what is your backlog pls comment.

Tuesday 22 September 2015

What Is SMS Gateway Server?

What Is SMS Gateway Server?


SMS server is designed to organize bilateral exchange with subscribers of GSM short text messages, dialed in English language.

SMS server is used in electronic payments made for awareness of the transaction, as well as for monitoring and control equipment. As part of call center service calls, SMS server is used to request a callback service (Call Back), and to automatically receive orders for goods, the activation of prepaid-cards, etc.

With SMS server distribution of information, taking questions, suggestions and requests from listeners of radio and television can be organized.
SMS server supports simultaneous work with 16 polytypic devices (any combination) and SMPP-connections (each connection is treated as a separate device) provides the ability to connect any number of client jobs.

SMS server software includes:
SMS Gateway server, implemented as NT service for operating systems, Microsoft Windows NT 4.0/2000/XP/2003/2008. SMS Gateway server provides support for multi-user configuration.

SMS Client – Win32 application that runs on all platforms supported by Microsoft MS Windows, ensures the exchange of SMS messages with SMS Gateway server. A set of COM components providing exchange protocols with supported types of GSM devices and SMS Gateway server.

Scheme of arrangement of the SMS server hosting:

SMS Gateway server provides
Reception and sending SMS messages via database servers; possibility of sending SMS messages in a batch mode from command line; SMS content analysis and ability to perform predetermined actions.
The SQL query is sent to an external database with substitution into the query the SMS message fields. Notification for connected clients on new SMS messages; Ability to get SMS delivery confirmation message; Interacting via SMPP protocol with GSM operator SMS center; The use of admission of SMS, depending on sender phone number prefix, keywords in SMS message, device, through which the message was accepted. SMS message delivery to rule-indicated users; Use of SMS sending rules is depending on the destination of phone number prefix. Sending SMS messages via rule-defined devices according to their priority and availability; Differentiation of access rights and rules to send and receive SMS.

SMS client provides
View received and sent SMS messages in accordance with specified criteria (outgoing, incoming, within the range of dates);  Delayed receive new messages; Creating and sending new SMS messages or sending SMS messages from the database to the specified phone numbers manually entered or selected from the built-in phone book; Sending SMS messages to a group of numbers.


Monday 21 September 2015

25 Great Secrets In Apple iOS 9


  1. 25 Great Secrets In Apple iOS 9


iOS 9 is here (in slightly controversial fashion) and with it come many great new features. But also inside every major Apple software release are hidden gems that separate the power users from the masses. It’s time to spill those secrets…
To make all these features easier to navigate I’ve grouped them by category:

Camera And Video
1. Zoom In Videos – Yes, with iOS 9 pinch to zoom not only works for photos but videos as well. Just perform the pinch gestures while a video is playing.

2. Hide Photos - You probably don’t want every photo you take to be easily viewable to anyone who picks up your phone and helpfully iOS 9 fixes this. In camera roll tap ‘Select’ and select all the photos you want to be hidden away then tap the bottom left corner button to open a Share Sheet and select ‘Hide’.



3. Fast Photo Selection - with iOS 9 you no longer need to tap individual photos for multiple selections. Just keep your finger on the screen after selecting the first photo and drag it to select as many as you want in a single action.

4. Fast Photo Scanning - you’re likely to build up a substantial photo library over time (unless you have the 16GB model) so once you open a photo in iOS 9 look for the strip of image thumbnails below. Drag this left or right to race through your snaps.

5. Easy Close Photo Shortcut – as iPhones get bigger it isn’t so easy to reach the top left ‘Back’ button, but iOS 9 eases this frustration by allowing you to swipe down on any open photo to return to the Camera Roll.

Battery Secrets
6. Hidden Battery Widget – iOS 9 lets you add a new battery widget to the bottom of the ‘Today’ view in the Notification Center. Tap ‘edit’ at the bottom of the Today column to reveal the option to add it. You will notice it also shows a connected Apple Watch.



7. Detailed Battery Usage - ever wondered which apps are killing your battery? Now you can get a detailed breakdown in iOS 9 by going to Settings > Battery then ‘Battery Usage’. These can also be broken down by the time using the Clock button.

8. Manually Enable Low Power Mode – Sometimes you may want to conserve power long before your iPhone or iPad is about to die. Turn the new Low Power Mode on manually by going to Settings > General > Battery > Low Power Mode and toggle it to On.

Quick access to call or message contacts.

10. Quick Reply – this feature was partially introduced in iOS 8, but now all messaging apps in iOS 9 allow quick replies to be sent by dragging down on a new message notification.



11. Group Notifications - prefer your notifications grouped by app rather than time? Easy in iOS 9! Settings > Notifications > Group By App and switch the toggle to On.

12. New Voices - iOS 9 has more voice options if you head to Settings > General > Accessibility > Voices.

13. Messages: Easy Close Attachments – As with photos, you can avoid using the hard-to-reach back button by swiping down on any open attachment to return to the message.

Safari Shortcuts

14. Smart Safari Search - paste a URL into the Safari address bar and it triggers the button ‘Paste and Go’, saving an extra tap. Similarly, paste any text into the Safari address bar and it gives you a single tap ‘Paste and Search’ button.

15. Desktop Mode Shortcut - Safari has long had a ‘request desktop site’ mode but now you can quickly access it in iOS 9 but tapping and holding your finger on the address bar to bring up the ‘Request Desktop Site’ option.



16. Enhanced Reader Mode – Reader Mode in Safari existed in iOS 8, but now you can also change the font, background and other options simply but tapping the ‘Aa’ button.

17. Save Website As PDF - while the likes of Pocket and Instapaper have become the defacto offline reading tools for millions, it can also be useful to save a website as a simple PDF. Open the Safari Share Sheet menu and you’ll now find ‘Save PDF to iBooks’.

18. AdBlock Shortcut - In iOS 9 if you long press the refresh icon in Safari it gives you the option to reload the page with ad blocking enabled.

Easier Input

19. Change keyboard caps - with iOS 9 Apple’s virtual keyboard keys adapt automatically to show upper and lower case fonts. This can be disabled by going to Settings > General > Accessibility > Keyboard and toggle ‘Show Lowercase Keys’ to off. I’d suggest this is more useful for pranks, than anything else.

20. Quick Calculator and Currency Conversions - like the Chrome browser, the Spotlight in iOS 9 now gives you answers to calculations and currency questions as you type.


21. Mutating Mute Switch – prefer to use the mute switch on your iPhone for something else? Go to Settings > General and you can instead set it to enable/disable screen rotation. This was an iPad only feature before iOS 9.

Pro Productivity

22. Markup Mail - Apple’s unloved Mail app finally has a useful new feature: after attaching a photo to an email simply tap and hold it to get the ‘Markup’ option, which lets you draw on it.

23. Wallet Privacy - Apple Pay automatically appears when you need it so there’s little point to Wallet’s annoying habit in iOS 9 of appearing on your lock screen if you double tap the home button. Settings > Touch ID & Passcode and toggle Wallet to Off.



24. Beat Slow WiFi – if your WiFi network is letting you down navigate to Settings > Cellular > Wi-Fi Assist to allow your iPhone or cellular iPad to boost performance by using carrier data in addition to WiFi.

25. Hidden iCloud - Strangely iOS 9 hides Apple’s new iCloud app by default. Reveal it by going to Settings > iCloud > iCloud Drive and toggle ‘Show on Home Screen’ to on for access to this useful service.


The Future of Remote Work, According to Startups

  The Future of Remote Work, According to Startups No matter where in the world you log in from—Silicon Valley, London, and beyond—COVID-19 ...