Quando pensamos em desenvolver um site temos que pensar primeiro em sua segurança. A primeira segurança que vem em nossas cabeças é colocar um controle de acesso a usuários. Pensamos que com isso o site já está protegido, mais esquecemos de uma coisa importante que é o que o usuário vai ter acesso. Com esse pensamento muitos desenvolvedores criam níveis de acesso ao site para determinados usuário, o que caracteriza o perfil.
No projeto website deste artigo será criada uma tabela de controle de acesso, onde teremos os dados do usuário para o acesso e o campo de perfil, que será estático e não terá tabela para serem criados e configurados novos perfis. Por ser estático, veremos como atribuir permissão a uma tela inteira ou a um método, isso para um usuário ou atribuindo o perfil que pode ter acesso.
Para o desenvolvimento será utilizado o Visual Studio 2013 e o banco de dados SQL Server 2012 (consulte a seção Links para ver os respectivos links).
Controle de Acesso
Criaremos primeiro o Banco de Dados que será responsável por armazenar a tabela de acesso e para isso usaremos o seguir:
CREATE DATABASE DEVMEDIA;
Após a criação do banco de dados criamos a tabela de ACESSO, responsável por armazenar as informações do acesso, conforme a Listagem 1.
USE DEVMEDIA
CREATE TABLE ACESSO(
ID_LOGIN INT IDENTITY NOT NULL,
EMAIL VARCHAR(100),
SENHA VARCHAR(100),
ATIVO CHAR(1),
PERFIL VARCHAR(15),
NOME VARCHAR(30),
SOBRENOME VARCHAR(30)
)
Após a criação da tabela iremos executar o script de insert para a criação dos usuários no site, conforme a Listagem 2.
INSERT INTO ACESSO (EMAIL, SENHA, ATIVO, PERFIL, NOME, SOBRENOME)
VALUES ('admin@admin.com', '123456', 'S', 'Administrador', 'Admin', 'Sistema')
INSERT INTO ACESSO (EMAIL, SENHA, ATIVO, PERFIL, NOME, SOBRENOME)
VALUES ('user@user.com', '123456', 'S', 'Usuario', 'User', 'Sistema')
Agora no Visual Studio iremos criar o projeto, conforme os passos da Figura 1.
Escolha a opção ASP.NET Web Application e dê o nome de Controle Acesso. Em seguida escolha o tipo de projeto que será criado que, no nosso caso, será um projeto Empty (Vazio), e utilizaremos a estrutura do MVC, como mostra a Figura 2. Não podemos esquecer de desmarcar a opção do Microsoft Azure, pois não iremos criar um site já hospedado.
Agora criaremos a conexão do banco de dados utilizando o Entity Framework. Para isso, basta clicar com o botão direito do mouse na pasta Model à Opção Add à New Item e a tela igual a Figura 3 aparecerá. Nela escolheremos a opção Data no navegador, que está na lateral esquerda, e no quadrado à direita escolha a opção ADO.NET Entity Data Model. O nome do projeto será ControleAcesso.cs.
Na próxima tela escolha a opção EF Designer from DataBase, que criará um projeto a partir de um banco de dados que iremos escolher. Aparecerá na próxima tela o botão “New Connection” e, ao clicar nele, irá aparecer a tela semelhante à Figura 4 para preencher algumas informações para conexão do banco de dados.
No campo Server name preencha com o nome do servidor do banco de dados. Caso esteja instalado localmente pode utilizar o nome do computador ou o localhost.
Não esqueça de marcar a opção de autenticação com o banco de dados: caso não tenha um usuário ou senha do banco basta escolher a primeira opção. Caso contrário, use a opção Use SQL Server Authentication para informar o usuário e senha de acesso ao bando de dados.
Após o preenchimento de todos os campos e escolhido o banco de dados, basta clicar em Test Connection: caso esteja tudo ok irá aparecer a mensagem Test Connection Succeeded. Ao final clique no botão OK.
Voltando para a tela de configuração da conexão, não esqueça de marcar a opção “Yes, include the sensitive data in the connection string” para gravar a senha na connection string no WebConfig do projeto. Clique no botão Next e escolha a opção Entity Framework 6.x.
Na Figura 5 selecione apenas a opção Tables e clique em Finish.
Com isso, o Model do seu banco de dados com todas as configurações já está pronto para o uso. Na Figura 6 vemos a conexão que foi criada no Entity Framework.
Agora vamos até a pasta do Controllers e criar um novo controle. Para isso basta clicar com o botão direito do mouse em cima da pasta Controllers à Add à Controller. Escolha o tipo MVC 5 Controller – Empty e dê o nome de HomeController.
Agora precisamos criar a Index do controlador. Para isso, basta abrir o HomeController que foi criado e ir no método public ActionResult Index() e clicar com o botão direito do mouse em cima de Index e escolher a opção Add View.
Na nova tela preencha as seguintes informações:
- View Name: Deve informar o nome da View, que no nosso caso vai ser Index;
- Template: Ao criar a View podemos escolher criar uma com a opção Empty (without model), ou com alguns métodos prontos para ser utilizado pelo controlador. Ficaremos com a primeira opção.
- Model Class: É utilizado quando vamos criar alguma View com opção de Create, Delete, List, Edit, etc. Não vamos preencher esse campo;
Dentre as Opções temos:
- Create as a partial view: No caso não iremos utilizar uma classe particionada e sim uma classe normal;
- Reference script libraries: Essa opção já fica preenchida, pois ela irá fazer a referência dos scripts que irá utilizar;
- Use a layout page: Essa opção no nosso caso ficará desmarcada, pois não iremos utilizar nenhum layout, mas vamos criar o nosso para teste de validação do usuário.
Crie também o controlador responsável pela parte de Login chamado AccountController. Este terá um método chamado public ActionResult Index (), mas iremos renomear este para Login ().Crie a view referente a nossa tela de login usando as mesmas configurações da tela de Home.
Antes de fazermos qualquer coisa na tela de login iremos fazer a instalação do framework Bootstrap. Para isso, iremos no nosso projeto e clicaremos com o botão direito do mouse sobre e escolher a opção Manage Nuget Packages, como ilustra a Figura 7.
Busque na pesquisa por bootstrap e pressione enter. Ela irá carregar vários plug-ins que podem ser utilizados, mas iremos escolher o bootstrap que apareceu primeiro, como mostra a Figura 8.
Para começar a tela de login vamos utilizar um CSS padrão presente na Listagem 3. Clique com o botão direito do mouse na pasta Content à Add à Style Sheet, e coloque o nome devmedia_estilo. Esse refere-se a tela de login aonde iremos criar um quadrado centralizado com dois Input Text e um Botão. Foi disponibilizado também o CSS presente na Listagem 3.
body {
background-color: #f0f0f0;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
color: #313131;
line-height: 1;
padding: 5px;
}
{
width: 100%;
height: 100%;
background-color: #2D333B;
}
.form-login {
max-width: 450px;
max-height: 350px;
margin-left: auto;
margin-right: auto;
padding: 10px;
border-radius: 10px;
margin-top: 10%;
}
.form-login input {
margin-bottom: 10px;
}
.btn {
display: inline-block;
padding: 6px 12px;
border: 2px solid #ddd;
color: #ddd;
text-decoration: none;
font-weight: 700;
text-transform: uppercase;
margin: 15px 5px 0;
transition: all .2s;
min-width: 100px;
text-align: center;
font-size: 14px;
}
.btn:hover, .btn.hover {
background: #ddd;
color: #777;
}
.btn.btn-lg {
padding: 10px 16px;
font-size: 18px;
}
.btn.btn-sm {
padding: 5px 10px;
font-size: 12px;
}
.btn.btn-xs {
padding: 1px 5px;
font-size: 12px;
padding: 1px 5px;
font-size: 12px;
}
.btn.primary {
border-color: #3498db;
color: #3498db;
}
.btn.primary:hover, .btn.primary.hover {
background: #3498db;
color: #fff;
}
.btn.danger {
border-color: #e74c3c;
color: #e74c3c;
}
.btn.danger:hover, .btn.danger.hover {
background: #e74c3c;
color: #fff;
}
.btn.success {
border-color: #27ae60;
color: #27ae60;
}
.btn.success:hover, .btn.success.hover {
background: #27ae60;
color: #fff;
}
.btn.warning {
border-color: #f1c40f;
color: #f1c40f;
}
.btn.warning:hover, .btn.warning.hover {
background: #f1c40f;
color: #fff;
}
.btn.black {
border-color: #34495e;
color: #34495e;
}
.btn.black:hover, .btn.black.hover {
background: #34495e;
color: #fff;
}
.btn.black {
border-color: #34495e;
color: #34495e;
}
.btn.black:hover, .btn.black.hover {
background: #34495e;
color: #fff;
}
.btn.info {
border-color: #5bc0de;
color: #5bc0de;
}
.btn.info:hover, .btn.info.hover {
background: #5bc0de;
color: #fff;
}
.btn.clear {
border-color: #777;
color: #777;
}
.btn.clear:hover, .btn.clear.hover {
background: #777;
color: #fff;
}
}
Vá a view de login e insira o código da Listagem 4. Em seguida compile o site.
@model Controle_Acesso.Models.ACESSO
@{
Layout = null;
}
<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<link href="~/Content/devmedia_estilo.css" rel="stylesheet" />
<script src="~/scripts/jquery-1.10.2.js"></script>
<script src="~/scripts/bootstrap.min.js"></script>
@using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post,
new { @class = "form-horizontal" }))
{
@Html.AntiForgeryToken();
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="container">
<div class="form-login">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Login do Sistema</div>
</div>
<div style="padding-top:30px" class="panel-body">
<div style="display:none" id="result" class="alert
alert-danger col-sm-12">
</div>
<div style="margin-bottom: 25px" class="input-group">
<span class="input-group-addon"><i class="glyphicon
glyphicon-user"></i></span>
@Html.EditorFor(model => model.EMAIL, new { htmlAttributes =
new { @class = "form-control input-lg", placeholder =
"E-mail", autofocus = true } })
@Html.ValidationMessageFor(model => model.EMAIL, "",
new { @class = "text-danger" })
</div>
<div style="margin-bottom: 25px" class="input-group">
<span class="input-group-addon"><i class="glyphicon
glyphicon-lock"></i></span>
@Html.EditorFor(model => model.SENHA, new { htmlAttributes
= new { @class = "form-control input-lg", placeholder = "Senha" } })
@Html.ValidationMessageFor(model => model.SENHA, "",
new { @class = "text-danger" })
</div>
<div style="margin-top:10px" class="form-group">
<div class="col-sm-12 controls">
<input type="submit" value="Acessar"
class="btn primary btn-lg" />
</div>
</div>
</div>
</div>
</div>
</div>
}
A compilação resultará na tela presente na Figura 9.
Precisamos alterar a URL para http://seusite/Home, assim abrirá a página home normalmente.
Criaremos agora a classe de ROLE para condicionar no projeto quem pode ter acesso ou não a uma determinada tela ou ação.
Para isso vai até a pasta model e crie uma nova classe chamada Role.cs. Ela vai fazer herança com a RoleProvider, mas para isso, na classe Role Provider declare o Using System.Web.Security:
public class Roles : RoleProvider
{
}
Após efetuar a herança copie o código da Listagem 5 e cole no projeto para implementar da classe RoleProvider.
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override string ApplicationName
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public override void CreateRole(string roleName)
{
throw new NotImplementedException();
}
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
{
throw new NotImplementedException();
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
throw new NotImplementedException();
}
public override string[] GetAllRoles()
{
throw new NotImplementedException();
}
public override string[] GetRolesForUser(string username)
{
DEVMEDIAEntities db = new DEVMEDIAEntities();
string sRoles = db.ACESSO.Where(p => p.EMAIL == username).FirstOrDefault().PERFIL;
string[] retorno = { sRoles };
return retorno;
throw new NotImplementedException();
}
public override string[] GetUsersInRole(string roleName)
{
throw new NotImplementedException();
}
public override bool IsUserInRole(string username, string roleName)
{
throw new NotImplementedException();
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override bool RoleExists(string roleName)
{
throw new NotImplementedException();
}
Abra o controlador HomeController e adicione o código Authorize logo no início da classe, isso porque queremos bloquear o acesso a página inteira. Caso queira restringir o acesso a alguns métodos basta colocar o Authorize em cima do método.
O Authorize está sem roles ainda, então todos os usuários que forem autenticados terão acesso a página ou método. Caso queira restringir para algum perfil ou perfis basta colocar o comando:
[Authorize(Roles = "Administrador")]
Assim, isso está condicionando a apenas Administradores o acesso a página Home.
Utilizando o comando a seguir:
[Authorize(Roles = "Administrador, Usuario")]
Este está condicionando o acesso aos perfis Administrador ou Usuário. Assim, o Authorize ficará como na Listagem 6.
[Authorize]
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}
}
Antes de compilar temos que fazer uma alteração no WebConfig da aplicação e adicionar as tags presentes na Listagem 7 dentro da tag .
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
<roleManager enabled="true" defaultProvider="Roles">
<providers>
<clear/>
<add name="Roles" type="Repositorio_Dados.Models.Roles"/>
</providers>
</roleManager>
A primeira tag authentication vai redirecionar para a página que estamos colocando na tag forms, sempre que encontrar um authorize e o usuário não estiver autenticado ou não tiver permissão.
A tag roleManager vai olhar para a nossa classe que foi criada para controle de permissão (Roles) e vai cuidar da validação de alguma permissão. Aqui, é importante observar que o caminho informado nessa tag refere-se ao nome da classe, incluindo seu namespace, e não necessariamente o caminho do arquivo no qual a classe está contida.
Agora vamos fazer a autenticação do usuário. Para isso vamos acessar o controller AccountController. Nele encontraremos o seguinte código:
public ActionResult Index()
{
return View();
}
Altere o mesmo e insira esse código da Listagem 8.
/// <param name="returnURL"></param>
/// <returns></returns>
public ActionResult Login(string returnURL)
{
/*Recebe a url que o usuário tentou acessar*/
ViewBag.ReturnUrl = returnURL;
return View(new ACESSO());
}
Implementamos o método login, que é responsável por redirecionar para a View de acesso. Ele pede como parâmetro uma returnURL que armazena qual é a URL atual para ser redirecionado após a autenticação.
Na Listagem 9 vemos o método que faz a validação e a autenticação do usuário.
/ <param name="login"></param>
/ <param name="returnUrl"></param>
/ <returns></returns>
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(ACESSO login, string returnUrl)
{
if (ModelState.IsValid)
{
using (DEVMEDIAEntities db = new DEVMEDIAEntities())
{
var vLogin = db.ACESSO.Where(p => p.EMAIL.Equals(login.EMAIL)).FirstOrDefault();
/*Verificar se a variavel vLogin está vazia.
Isso pode ocorrer caso o usuário não existe.
Caso não exista ele vai cair na condição else.*/
if (vLogin != null)
{
/*Código abaixo verifica se o usuário que retornou na variavel tem está
ativo. Caso não esteja cai direto no else*/
if (Equals(vLogin.ATIVO, "S"))
{
/*Código abaixo verifica se a senha digitada no site é igual a
senha que está sendo retornada
do banco. Caso não cai direto no else*/
if (Equals(vLogin.SENHA, login.SENHA))
{
FormsAuthentication.SetAuthCookie(vLogin.EMAIL, false);
if (Url.IsLocalUrl(returnUrl)
&& returnUrl.Length > 1
&& returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//")
&& returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
/*código abaixo cria uma session para armazenar o nome do usuário*/
Session["Nome"] = vLogin.NOME;
/*código abaixo cria uma session para armazenar o sobrenome do usuário*/
Session["Sobrenome"] = vLogin.SOBRENOME;
/*retorna para a tela inicial do Home*/
return RedirectToAction("Index", "Home");
}
/*Else responsável da validação da senha*/
else
{
/*Escreve na tela a mensagem de erro informada*/
ModelState.AddModelError("", "Senha informada Inválida!!!");
/*Retorna a tela de login*/
return View(new ACESSO());
}
}
/*Else responsável por verificar se o usuário está ativo*/
else
{
/*Escreve na tela a mensagem de erro informada*/
ModelState.AddModelError("", "Usuário sem acesso para usar o sistema!!!");
/*Retorna a tela de login*/
return View(new ACESSO());
}
}
/*Else responsável por verificar se o usuário existe*/
else
{
/*Escreve na tela a mensagem de erro informada*/
ModelState.AddModelError("", "E-mail informado inválido!!!");
/*Retorna a tela de login*/
return View(new ACESSO());
}
}
}
/*Caso os campos não esteja de acordo com a solicitação retorna a tela de login
com as mensagem dos campos*/
return View(login);
}
Na linha 08 o método valida os campos da tela e caso esteja tudo de acordo com as regras, ele retorna true e passa para o próximo passo. Caso contrário, ele cai no else do if*/
Na linha 10 o método cria a variável db, que recebe o EF. Ele é utilizado para não termos que destruir o objeto que foi criado. O mesmo, por padrão, quando deixa de ser utilizado é eliminado memória.
A variável da linha 12 é responsável por receber os dados da tabela de Acesso, que é retornado após a condição where. Como parâmetro usamos a variavel login.Email, que é o retorna da tela de login.
A partir da linha 25 temos que caso o usuário e senha estejam validados e o usuário esteja ativo, ele faz a autenticação do usuário gravando no Cookie a senha do usuário e o parâmetro False, que é utilizado pois sempre que o usuário fechar o navegador e abrir ele pede a autenticação novamente. Caso o parâmetro seja true, sempre que o usuário entrar no navegador e digitar a página, ele já vai entrar direto sem autenticação. Isso é um risco, pois pessoas mal-intencionadas consegue descriptografar o cookie e consegue pegar o usuário gravado.
O if da linha 26 faz a verificação da string do site, isso por causa da segurança na hora do retorno. Caso o parâmetro returnURL seja maior que 1, significa que existe uma string. Após isso, ele verifica se inicia com uma barra, que é o padrão. Caso retorne duas barras é errado e ele não valida, e por último ele verifica.
Agora, para efetuarmos os demais testes, criaremos a classe Acesso completa utilizando o Scaffold.
O Scaffold é capaz de gerar telas e controladores para as operações de inserção, leitura, alteração e remoção, chamado (CRUD), a partir de uma entidade. Os controladores gerados podem utilizar as funcionalidades do Entity Framework para interagir como banco de dados.
Para isso, clique com o botão direito em cima da pasta Controllers, escolha a opção ADD e depois Controler, que irá abrir uma tela parecida com a Figura 10.
Escolha a opção que está com a seta na frente MVC 5 Controller with views, using Entity Framework.
Após escolhida a opção solicitada irá abrir uma tela parecida com a Figura 11.
Na tela da Figura 11 temos os seguintes campos:
- Model Class: Nesse campo selecionaremos em qual entidade iremos criar os controladores com as views;
- Data contexto class: Nesse campo informamos qual é o EF que utilizaremos, tendo em vista que podemos ter mais de um EF no projeto;
- Use async contoller actions: Deixaremos desmarcados, pois não utilizaremos essa opção agora;
- Generate Views: Deixamos essa opção marcada, pois iremos criar as views para cada controlador;
- Reference script libraries: não marcaremos essa opção, pois só acrescentaremos as referências a jquery.validate.min.js e jquery.validate.unobtrusive.min.js;
- Use a layout page: Essa opção não marcaremos, pois não utilizaremos nenhum tipo de layout padrão;
- Controller name: Nome do controlador a ser criado;
Após efetuado o preenchimento de todos os dados iremos clicar em ADD e assim criaremos o Controller AcessoControler com as Views (Create, Delete, Details, Edit e Index). A Figura 12 ilustra como ficará.
Para iniciarmos os testes na Views Home iremos adicionar o código da Listagem 10.
@{
Layout = null;
}
<div class="container" style="text-align:center">
<div class="row" style="margin-top:10px">
<h2>DEVMEDIA</h2>
@if (Session["Nome"] != null)
{
<p><h3>Bem vindo ao sistema</h3> <h1>
@Session["Nome"].ToString() @Session["Sobrenome"].ToString()</h1></p>
<p>@Html.ActionLink("Cadastro de Acesso", "Index", "Acesso")</p>
}
</div>
</div>
Após inserir o código na View e compilarmos, o resultado será igual a Figura 13.
Após executar e ter o resultado informado, basta clicar no link Cadastro de Acesso, assim, a página Index será exibida como está no ActionLink. Essa classe traz a lista de usuários cadastrados, como ilustra a Figura 14.
Agora vamos aplicar a autorização para alguns métodos como o Edit e o Delete.
Iremos informar no código que só terá acesso a essas telas se o usuário for administrador, caso não seja, iremos redirecionar para a tela de Login. Para isso, colocaremos o método [Authorize(Roles = "Administrador")] em cima do método Edit e Delete, como ilustra as Listagens 11 e 12.
[Authorize(roles = “Administrador”)]</p>
[Authorize(roles = “Administrador”)]
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatus.BadRequest);
}
ACESSO aCESSO = db.ACESSO.Find(id);
If (aCESSO == null)
{
return HttpNotFoud();
}
return View(aCESSO);
}
[Authorize(Roles = “Administrador”)]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Bind(Include = “ID_LOGIN, EMAIL, SENHA, ATIVO,
PERFIL, NOME, SOBRENOME”)] ACESSO aCESSO)
{
if (ModelState.IsValid)
{
db.Entry(aCESSO).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction(“Index”);
}
return View(aCESSO);
}
No controler Acesso encontraremos dois métodos Edits: o primeiro trata-se de acesso a tela de editar e o segundo método Edit é a ação executada ao clicar no botão de Save da tela de Edit.
[Authorize(Roles = “Administrador”)]
public ActionResult Delete(int? id)
{
if (id ==null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
ACESSO aCESSO = db.ACESSO.Find(id);
if (aCESSO == null)
{
return HttppNotFound();
}
return View(aCESSO);
}
[Authorize(Roles = “Administrador”)]
[HttpPost, ActionName(“Delete”)]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
ACESSO aCESSO = db.ACESSO.Find(id);
db.ACESSO.Remove(aCESSO);
db.SaveChanges();
return RedirectToAction(“Index”);
}
No controller Acesso encontraremos dois métodos delete: o primeiro trata-se de acesso a tela de delete e o segundo método é a ação ao clicar no botão de Save da tela de Edit.
Após a alteração, basta salvar o projeto, compilar novamente e efetuar os testes na tela com o usuário e perfil de Administrador clicando em editar e delete. Em seguida, faça o teste com o usuário e perfil de Usuário e verá que sempre que ao clicar em editar ou delete será redirecionado para a tela de Login.
Saiu na DevMedia!
- JSF e Hibernate: Como implementar um CRUD: Neste curso você aprenderá a construir uma aplicação de cadastro de lembretes, que gravará essas informações em um banco de dados MySQL.
- ASP.NET Web API e OData: Como criar filtros e ordenação: Neste microexemplo veremos como utilizar o pacote OData para adicionar funcionalidades de filtro, ordenação, paginação e seleção de campos no ASP.NET Web API. Confira!
- O que é Java?: Neste curso você aprenderá o que é o Java, tecnologia para desenvolvimento de software mais utilizada pelos programadores em todo o mundo.
Saiba mais sobre ASP.NET ;)
- ASP.NET MVC: Neste Guia de Referência você encontrará o conteúdo que precisa para aprender a desenvolver aplicações web com o framework ASP.NET MVC e a linguagem C#.
- ASP.NET Web API: Neste Guia de Referência você encontrará o conteúdo que precisa para aprender a desenvolver web services RESTful com o framework ASP.NET Web API e a linguagem C#.