Skip to content

Commit

Permalink
Connected Redux TodoMVC with Web API todo backend
Browse files Browse the repository at this point in the history
  • Loading branch information
martijnboland committed Dec 9, 2015
1 parent a95ff07 commit ebaa587
Show file tree
Hide file tree
Showing 18 changed files with 641 additions and 14 deletions.
24 changes: 24 additions & 0 deletions VSReact.Api/App_Start/JsonContentNegatiator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;

namespace VSReact.Api.App_Start
{
public class JsonContentNegotiator : IContentNegotiator
{
private readonly JsonMediaTypeFormatter _jsonFormatter;

public JsonContentNegotiator(JsonMediaTypeFormatter formatter)
{
_jsonFormatter = formatter;
}

public ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
{
var result = new ContentNegotiationResult(_jsonFormatter, new MediaTypeHeaderValue("application/json"));
return result;
}
}
}
24 changes: 21 additions & 3 deletions VSReact.Api/App_Start/WebApiConfig.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Formatting;
using System.Web.Http;
using System.Web.Http.Cors;
using VSReact.Api.App_Start;

namespace VSReact.Api
{
Expand All @@ -10,15 +15,28 @@ public static class WebApiConfig
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings = new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};


// JSON only
config.Services.Replace(typeof(IContentNegotiator), new JsonContentNegotiator(json));

// Web API routes
config.MapHttpAttributeRoutes();

config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
}
88 changes: 88 additions & 0 deletions VSReact.Api/Controllers/TodoController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace TodoMvc.Controllers
{
public class TodoController : ApiController
{
private readonly Data.TodoRepository repo;

public TodoController()
{
repo = new Data.TodoRepository();
}

// GET: Todo
public IEnumerable<Models.Todo> Get()
{
var items = repo.GetAll();

foreach (var t in items)
{
t.Url = String.Format("{0}/{1}", Request.RequestUri.ToString(), t.Id.ToString());
}

return items;
}

// GET: Todo/5
public Models.Todo Get(int id)
{
var t = repo.Get(id);
if (t != null)
{
t.Url = Request.RequestUri.ToString();
}
return t;
}

// POST: Todo
public HttpResponseMessage Post(Models.Todo item)
{
var t = repo.Save(item);
t.Url = String.Format("{0}/{1}", Request.RequestUri.ToString(), t.Id.ToString());

var response = Request.CreateResponse<Models.Todo>(HttpStatusCode.OK, t);
response.Headers.Location = new Uri(Request.RequestUri, "todo/" + t.Id.ToString());

return response;
}

// PATCH: Todo/5
public HttpResponseMessage Patch(int id, Models.Todo item)
{
var todo = repo.Get(id);
if (item.Title != null)
{
todo.Title = item.Title;
}
if (item.Completed.HasValue)
{
todo.Completed = item.Completed;
}
var t = repo.Save(todo);
t.Url = Request.RequestUri.ToString();

var response = Request.CreateResponse<Models.Todo>(HttpStatusCode.OK, t);
response.Headers.Location = new Uri(Request.RequestUri, t.Id.ToString());

return response;
}

// DELETE: Todo
public void Delete()
{
repo.Delete();
}

// DELETE: Todo/5
public void Delete(int id)
{
repo.Delete(id);
}
}
}
27 changes: 27 additions & 0 deletions VSReact.Api/Models/Todo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace TodoMvc.Models
{
public class Todo
{
public int Id { get; set; }
public int? Order { get; set; }
public string Title { get; set; }
public string Url { get; set; }
public bool? Completed { get; set; }

public override bool Equals(object obj)
{
var todo = obj as Todo;
return (todo != null) && (Id == todo.Id);
}

public override int GetHashCode()
{
return Id.GetHashCode();
}
}
}
57 changes: 57 additions & 0 deletions VSReact.Api/Models/TodoRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace TodoMvc.Data
{
public class TodoRepository
{
public static List<Models.Todo> Todos = new List<Models.Todo>();
public static int MaxId = 0;

public IEnumerable<Models.Todo> GetAll()
{
return Todos.OrderByDescending(t => t.Order);
}

public Models.Todo Get(int id)
{
return Todos.Where(t => t.Id == id).FirstOrDefault();
}

public Models.Todo Save(Models.Todo item)
{
if (item.Id == 0)
{
item.Id = ++MaxId;
if (!item.Order.HasValue)
{
item.Order = item.Id;
}
}

int index = Todos.IndexOf(item);
if (index != -1)
{
Todos[index] = item;
}
else
{
Todos.Add(item);
}

return item;
}

public void Delete()
{
Todos.Clear();
}

public void Delete(int id)
{
Todos.RemoveAll(t => t.Id == id);
}
}
}
12 changes: 10 additions & 2 deletions VSReact.Api/VSReact.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Web.Cors">
<HintPath>..\packages\Microsoft.AspNet.Cors.5.2.3\lib\net45\System.Web.Cors.dll</HintPath>
</Reference>
<Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" />
<Reference Include="System.Web.ApplicationServices" />
Expand All @@ -58,6 +61,9 @@
<Reference Include="System.Core" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Web.Http.Cors">
<HintPath>..\packages\Microsoft.AspNet.WebApi.Cors.5.2.3\lib\net45\System.Web.Http.Cors.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
Expand Down Expand Up @@ -85,10 +91,14 @@
<Content Include="Web.config" />
</ItemGroup>
<ItemGroup>
<Compile Include="App_Start\JsonContentNegatiator.cs" />
<Compile Include="App_Start\WebApiConfig.cs" />
<Compile Include="Controllers\TodoController.cs" />
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
<Compile Include="Models\Todo.cs" />
<Compile Include="Models\TodoRepository.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
Expand All @@ -102,8 +112,6 @@
</ItemGroup>
<ItemGroup>
<Folder Include="App_Data\" />
<Folder Include="Controllers\" />
<Folder Include="Models\" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
Expand Down
2 changes: 2 additions & 0 deletions VSReact.Api/packages.config
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.Cors" version="5.2.3" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Cors" version="5.2.3" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi" version="5.2.3" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net46" />
Expand Down
21 changes: 21 additions & 0 deletions VSReact.Web/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"ecmaFeatures": {
"jsx": true,
"modules": true
},
"env": {
"browser": true,
"node": true
},
"parser": "babel-eslint",
"rules": {
"quotes": [2, "single"],
"strict": [2, "never"],
"react/jsx-uses-react": 2,
"react/jsx-uses-vars": 2,
"react/react-in-jsx-scope": 2
},
"plugins": [
"react"
]
}
29 changes: 27 additions & 2 deletions VSReact.Web/VSReact.Web.csproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.Default.props" Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.Default.props')" />
<Import Project="..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props" Condition="Exists('..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" />
<Import Project="..\packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props" Condition="Exists('..\packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
Expand All @@ -24,6 +25,7 @@
<UseGlobalApplicationHostFile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<TypeScriptToolsVersion>1.7</TypeScriptToolsVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
Expand Down Expand Up @@ -67,6 +69,9 @@
</ItemGroup>
<ItemGroup>
<Content Include=".babelrc" />
<Content Include="app\actions\TodoActionsAsyncBackend.js" />
<Content Include="app\index.js" />
<Content Include="app\reducers\todosAsyncBackend.js" />
<Content Include="package.json" />
<Content Include="README.md" />
</ItemGroup>
Expand All @@ -82,7 +87,6 @@
<Content Include="app\containers\App.js" />
<Content Include="app\containers\TodoApp.js" />
<Content Include="index.html" />
<Content Include="app\index.js" />
<Content Include="app\reducers\index.js" />
<Content Include="app\reducers\todos.js" />
<Content Include="server.js" />
Expand All @@ -91,12 +95,33 @@
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Service Include="{4A0DDDB5-7A95-4FBF-97CC-616D07737A77}" />
</ItemGroup>
<ItemGroup>
<Content Include=".eslintrc" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<TypeScriptTarget>ES6</TypeScriptTarget>
<TypeScriptJSXEmit>React</TypeScriptJSXEmit>
<TypeScriptCompileOnSaveEnabled>False</TypeScriptCompileOnSaveEnabled>
<TypeScriptNoImplicitAny>False</TypeScriptNoImplicitAny>
<TypeScriptModuleKind>System</TypeScriptModuleKind>
<TypeScriptRemoveComments>False</TypeScriptRemoveComments>
<TypeScriptOutFile />
<TypeScriptOutDir />
<TypeScriptGeneratesDeclarations>False</TypeScriptGeneratesDeclarations>
<TypeScriptNoEmitOnError>True</TypeScriptNoEmitOnError>
<TypeScriptSourceMap>True</TypeScriptSourceMap>
<TypeScriptMapRoot />
<TypeScriptSourceRoot />
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets" Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets')" />
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
<ProjectExtensions>
Expand Down
Loading

0 comments on commit ebaa587

Please sign in to comment.