Tag Archives: App Model
SAAM – Site Asset App Model
Developers have more options in SharePoint 2013 than any version before. App Model is center stage. Understandably this has created some confusion and debate in the community. I’d like to suggest another coding pattern to consider in addition to pure App Model which I call “Site Asset App Model.”
Long before SP2013 released, I would add jQuery “widgets” to pages in MOSS2007 and SP2010 with a Content Editor. Upload HTML, CSS, and JS files. Simple and effective. Requires no special infrastructure changes. This approach remains valid and has actually improved with advancements like :
- JavaScript frameworks
- Angular, Knockout
- HTML 5 browsers
- REST /_api/ endpoints
- ASP.Net WebAPI
- Entity Framework
- BreezeJS
I might not always use pure “App Model”, but I’m 100% sold on JavaScript front end development and the “from Bricks to Houses” philosophy (http://channel9.msdn.com/Events/SharePoint-Conference/2014/SPC404) Call this whatever name you like, but JavaScript coding has advantages for both developers and administrators alike. I suggest coding JS first, then fallback to C# wrapped in WebAPI over HTTP, and finally farm solution WSP as last resort.
Please leave a comment if you found this helpful! ![]()
Diagram
How to Use
Configure
- Create new folder in Site Assets
- Map drive letter
- Create HTML/JS/CSS files with local IDE (Visual Studio, Brackets, NotePad++, etc.)
- Add page to SharePoint site
- Add Content Editor to page. Set source Property to HTML location.
Debug
- Edit source HTML/JS/JSS
- Reload with browser
- Press F12 to debug, set breakpoints, inspect DOM
- NOTE – adding the JS statement “debugger;” can help raise a local browser event. That can be a nice trick to more easily create breakpoints in your editor instead of scrolling the same codebase again with F12. http://www.w3schools.com/js/js_debugging.asp
Admittedly there are drawbacks:
- No Visual Studio F5 debug
- No full package (.APP)
- No Office365 store
- No app-only principal (limited to current user permissions)
- Hard to deploy multiple instances
However, there might be times when SAAM is preferred:
- Working on SP2007/2010
- Lacking SP2013 App Model infrastructure (Wildcard DNS, Service Apps, etc.)
- Visual Studio not available (required for .APP package/deploy)
- Non-SharePoint developers comfortable editing HTML/JS/CSS directly
Comparison Table
| Feature | SP2013 “App Model” | Site Assets App Model (SAAM) |
| HTTP call host web without SP Request Executor Proxy | NO | YES |
| Support REST to External Content Types made in SharePoint Designer | NO | YES |
| List and Library user data kept if app uninstalled (code upgrade) | NO | YES |
| Create standard Views for lists and libraries with App user data | NO | YES |
| Works on SP2007 and 2010 older versions | NO | YES |
| Restricted to “App Web” where many features disabled | YES | NO |
| Requires server infrastructure changes | YES | NO |
| * Claims authentication | YES | NO |
| * Wildcard DNS on network | YES | NO |
| * Service Applications | YES | NO |
| * Additional SQL databases and service accounts | YES | NO |
| Requires security manifest | YES | NO |
| * Permissions plan to use | YES | NO |
| * Web service endpoint URLs | YES | NO |
| Able to publish and sell in Office 365 Store | YES | NO |
| Able to use App Identity Security Principal | YES | NO |
SP2013 “App Model” | Site Assets App Model (SAAM) |
References
http://channel9.msdn.com/Events/Speakers/Scot-Hillier
- ”From bricks to houses” > wider view beyond “App Model” looking at all front end coding (JS/REST)
http://www.itunity.com/community/questions/view/question/id/1
- Use SharePoint where it makes sense (components ready), but now able to include a wider menu of 3rd party technology choices.
- Non-Microsoft, Google, others, and a whole web of innovation beyond SP core.
- Detailed comparison table
- Yes, some things cannot be done in “App Model”
- Yes, farm solutions are still valid (but as a last resort – try front end coding first)
http://sharepointpromag.com/blog/sharepoint-2013-s-cloud-app-model-it-s-what-you-wanted-all-along
- And ultimately, it’s going to be moot. In multi-tenant environments such as Office 365, this is the only real option.
- Office365 is the gold standard for low administrative effort.
BreezeJS – Edit SQL table with < 100 lines of JS code [VIDEO]
With SharePoint 2013 and industry movement towards the cloud I’ve been exploring JavaScript as a primary way to develop rich applications.
One common challenge is data access.
With C# I have years of experience with [System.Data] and can perform CRUD against SQL relational databases in my sleep. Open connection, query, data adapter, fill DataTable, and voila! Muscle memory. Second nature. Tried and true methods. However, in the new client side JS world I had no clue where to begin.
Enter Breeze.
People describe Breeze as “Entity Framework on the client in JavaScript” which sounds simple yet has profound implication for the developer. CRUD operations, LINQ style query, navigating primary/foreign keys, input validation, caching, batch updates, and more. That’s a lot to consider and new ideas take time to absorb. Breeze could potentially replace:
- ASP.Net (ASPX) web forms
- ASCX user controls
- InfoPath forms
- SharePoint web parts
- WCF 5.6 data services
- OData
- Classic WebAPI

I set out to code an example with a few goals:
- Create simple SQL schema (two tables – parent/child – one to many)
- Execute CRUD operations in JS against SQL tables
- Leverage JS plugins and NuGet “Install-Package” to load third party components
- Install-Package breeze.webapi2.ef6
- Install-Package breeze.angular
- Install-Package angularjs.core
- Little code as possible
The whole thing took less than 30 minutes and I edited video down to just 15. I was impressed by how straightforward and easy the process was. Breeze# in ASP.Net MVC for the back end WebAPI controller was nearly identical to the Breeze example code. Add one C# method per entity (SQL table) and Breeze does the rest. The JS front end took a little more time to understand but was also easy to apply. Connect Entity Manager to the Breeze URL and you’re ready for CRUD queries. Amazing! Given how easy Breeze is I would be hard pressed to use OData or manually created WebAPI controllers with C# code to query a database. If you can use Breeze, then use it! You’ll save lots of effort.
Please leave a comment if you found this helpful. Thank you! ![]()
Watch Video
[BreezeJS and WebAPI – Edit SQL table in JS with less than 100 lines of code]
Download Code
http://spjeff.com/etc/Appraisal-Breeze-VS2013.zip |
Screenshots
References
- http://breeze.github.io/doc-samples/web-api-odata.html
- https://www.nuget.org/packages/Breeze.WebApi2.EF6/
- https://www.nuget.org/packages/Breeze.Angular/
- https://www.nuget.org/packages/AngularJS.Core/
- https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en
- http://www.microsoft.com/en-us/server-cloud/products/sql-server-editions/sql-server-express.aspx
- http://www.visualstudio.com/products/visual-studio-community-vs
- http://www.getbreezenow.com/samples/introduction-single-page-apps-sharepoint
- http://www.getbreezenow.com/samples/todo-angular

SharePoint 2013 – App Model 3 Tier Diagram
I needed a quick reference to introduce developers with the SharePoint 2013 App Model.
For traditional ASP.Net and Dot Net coders there is a wide philosophy gap to cross when considering new applications written mostly in front-end JavaScript, HTML, and CSS. Instead of coding “in” SharePoint (to augment the core product) we now code “next to” SharePoint (with additive REST/JSON endpoints).
The stability which comes from this approach is significant. We wan to run on-premise SharePoint similar to how Microsoft operates Office 365. No more SharePoint customization lost during patching. No more late night WSP and IISRESET outages. Code can be modified more fluidly and IE breakpoints can even be set at a single user’s desktop when troubleshooting. Exciting and powerful tools – which require a new way of thinking.
Please fee free to download the poster I made below. Hope you find it helpful! ![]()
WebAPI OData – 10 min video introduction (Visual Studio 2013)
I’ve been learning about OData and wanted to record a quick getting started video with how to create a new WebAPI project, add OData Controller, and send HTTP CRUD operations. Below is an example using Adventure Works Departments with sample code, screenshots, and a 10 minute video introduction. Please leave a comment if you found this helpful. Thanks! ![]()
Video Content
- Create MVC 4 web application
- SQL Express – Adventure Works Departments
- Add “AdventureWorks.edmx”
- Wizard driven
- F4 set namespace
- Add “DepartmentsController.cs”
- Create from EDMX class
- Implements ODataController
- Replace ID with KEY
- Edit “WebApiConfig.cs”
- Comment out default route
- Add OData route builder
- Test with HTTP manually
- Test with Chrome REST Postman
- SQL Express – see changed data
Watch Video
WebAPI OData – 10 min video introduction (Visual Studio 2013) from Jeff Jones on Vimeo.
Sample Code
[WebApiConfig.cs]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.Http.OData.Builder;
namespace MvcApplication1
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{controller}/{id}",
// defaults: new { id = RouteParameter.Optional }
//);
ODataConventionModelBuilder build = new ODataConventionModelBuilder();
build.EntitySet("Departments");
config.Routes.MapODataRoute("odata", "odata", build.GetEdmModel());
config.EnableQuerySupport(new QueryableAttribute());
// Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable return type.
// To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries.
// For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712.
//config.EnableQuerySupport();
// To disable tracing in your application, please comment out or remove the following line of code
// For more information, refer to: http://www.asp.net/web-api
config.EnableSystemDiagnosticsTracing();
}
}
}
[DepartmentsController.cs]
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using System.Web.Http.OData;
namespace MvcApplication1.Controllers
{
public class DepartmentsController : ODataController
{
private AdventureWorks2012Entities db = new AdventureWorks2012Entities();
// GET api/Default1
public IEnumerable GetDepartments()
{
return db.Departments.AsEnumerable();
}
// GET api/Default1/5
public Department GetDepartment(short key)
{
Department department = db.Departments.Find(key);
if (department == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
return department;
}
// PUT api/Default1/5
public HttpResponseMessage PutDepartment(short key, Department department)
{
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
if (key != department.DepartmentID)
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
db.Entry(department).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
// POST api/Default1
public HttpResponseMessage PostDepartment(Department department)
{
if (ModelState.IsValid)
{
db.Departments.Add(department);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, department);
response.Headers.Location = new Uri(Url.Link("odata", new { key = department.DepartmentID }));
return response;
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
// DELETE api/Default1/5
public HttpResponseMessage DeleteDepartment(short key)
{
Department department = db.Departments.Find(key);
if (department == null)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
db.Departments.Remove(department);
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
}
return Request.CreateResponse(HttpStatusCode.OK, department);
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}


