ict.ken.be

Delivering solid user friendly software solutions since the dawn of time.

Building Apps with Angular and Breeze - Notes 

Categories: Angularjs WebApi

by John Papa

Links:

SPA

  • Reach, Rich, Reduced Round Tripping
  • Navigation, History, Deep Linking, Persisting State, Most Load On Initial Response, Progressive Loading When Needed

Techniques

  • Dependency Injection
  • Routing
  • MV*
  • Data Binding
  • Publisher/Subscriber
  • DOM Templates
  • Views

Value

  • Reduces the plumbing
  • Handles the monotony
  • Spend more time on what matters
  • Focus on the user stories

Solution Structure

  • Server Models
  • Data Access (Entity Framework)
  • Web Server
  • HTML/CSS/Javascript + ASP.NET WebAPI
  • Modules
  • Startup Code
  • Twitter Bootstrap
  • Angular
  • Services

Unblock file: use alt + enter
Build: ctrl + shift + B

Hot Towel

  • AngularJS.Animate
  • AngularJS.Core
  • AngularJS.Route
  • AngularJS.Sanitize
  • FontAwesome
  • HotTowel.Angular
  • jQuery
  • Moment.js
  • Spin.js
  • toastr
  • Twitter.Bootstrap

Scripts OR vendor ?
app
app/config.js OR startup ?
app/config.exceptionhandler.js
app/config.route.js
app/layout/shell.html
app/services/datacontext.js
app/services/directives.js OR subfolders ?
index.html
ie10mobile.css
initial splash page
minify and bundle before production deploy

var app = angular.module('app', ['ngRoute']):
app.Value('config', config);
app.config(['$logProvider', function ($logProvider) ... ]) //runs before app.run
app.run(['$route', function ($route) {}]);

app.config(function ($provide) { $provide.decorator('$exceptionHandler', ['$delegate', 'config', 'logger', extendExceptionHandler]);});

app.constant('routes', getRoutes());

<div data-ng-include="'/app/layout/shell.html'"></div>
<div data-ng-view class="shuffle-animation"></div>

Angular v1.2 supports controller as: <section id="dashboard view" class="mainbar" data-ng-controller="dashboard as vm">

<section data-ng-controller="sessions as vm">
<div data-ng-repeat="s in vm.sessions" data-ng-click="vm.gotoSession(s)">
<div data-cc-widget-header title="{{vm.title}}"></div>

Directives can be A-Attribute, E-Element, C-Class, M-Comment

<img data-ng-src="..." />

GetDataPartials (as projection) -> map it into an existing entity -> extend this entity
metadataStore.registerEntityTypeCtor('Person', Person);
function Person() {
this.isSpeaker = false;
}

Breeze caches data locally in memory.
if (_areSessionsLoaded() && !forceRemote) {
sessions = _getAllLocal(entityNames.session, orderBy);
return $q.when(sessions); //transform it into a promise
}

function _areSessionsLoaded(value) {
...
}
function _areItemsLoaded(key, value) {
if (value == undefined) {
return storeMeta.isLoaded[key]; //get
}
return storeMeta.isLoaded[key] = vlaue;
}

Entity types are not necessary real resources. (extendMetadata)
Eg. Speakers, Attendees all users but different entities.

Make more responsive: class="hidden-phone"

Sharing Data: creating object graphs on the client

Routing:
$locationChangeStart
$routeChangeStart
$routeChangeSuccess
$routeChangeError
definition.resolve = angular.extend(definition.resolve || {}, { prime: prime });

Filtering:
<input data-ng-model="vm.search">
<div data-ng-repeat="s in vm.speakers | filter:vm.search">

<input ng-model="search.$">
<input ng-model="search.name">
<div data-ng-repeat="friends in friends | filter:search:strict">

vm.search = function($event) {
if($event.keyCode == config.keyCodes.esc) {
vm.speakerSearch = '';
}
applyFilter();
}

function speakerFilter(speaker) {
var isMatch = vm.speakerSearch
? common.textContains(speaker.fullName, searchText)
:true;
return isMatch;
}

Breeze & UI-Bootstrap:
<pagination boundry-links="true"
on-select-page="vm.pageChanged(page)"
total-items="vm.attendeeFilteredCount"
items-per-page="vm.paging.maxPagesToShow"
class="pagination-small"
previous-text=Prev"
next-text="Next"
first-text="First"
last-text="Last"
</pagination>

.executeLocally()

Dashboard:

  • Promises, Responsive Layout, Just the counts, Local and Remote Queries

.take(0).inlineCount()
_getAllLocal(...)

<th><a data-ng-click="vm.content.setSort('track')" ...
<tr data-ng-repeat="t in vm.content.tracks | orderBy:vm.content.predicate:vm.content.reverse">

ES5's.reduce() funciton will help create the mapped object
sessions.reduce (function (accum, session) {
var trackname = session.track.name;
var trackId = session.track.id;
if (accum[trackId-1]) accum[trackId-1].count++;
else accum[trackId-1] = { track: trackName, count: 1 }
}, []);

Animations (ngAnimate):

hide ngHide .ng-hide-add (start) .ng-hide-add-active (end)
show ngShow .ng-hide-remove .ng-hide-remove-active

Splash page in index.html
-> move to shell.html
-> turn off in activateController().then(...)

ngRepeat, ngInclude, nglf, ngView
enter .ng-enter .ng-enter-active
leave .ng-leave .ng-leave-active
move .ng-move .ng-move-active (only for ng-repeat)

http://www.yearofmoo.com (keyframe animations)
http://jpapa.me/yomanimations

DataContext will grow -> Repositories

http://johnpapa.net/protoctor

function gotoSpeaker(speaker) {
if (speaker && speaker.id) {
$location.path('/speaker/' + speaker.id);

}
}

Object.defineProperty(vm, 'canSave', {
get: canSave
});
function canSave() { return !vm.isSaving; }

function goBack() { $window.history.back(); }

function onDestroy() {
$scope.$on('$destroy', function() { datacontext.cancel(); });
}

manager.hasChangesChanged.subscribe(function(eventArgs){
... eventArgs.hasChanges ...
common.$broadcast(events.hasChangesChanged, data);
});

<select data-ng-options="t.name for t in vm.tracks"
data-ng-model="vm.session.track">
</select>

function createNullo(entityName) {
var initialValues = {
name: ' [Select a ' + entityName.toLowerCase() + ']'
}:
return manager.createEntity(
entityName, initialValues, breeze.EntityState.Unchanged);
);
}

Object.defineProperty(TimeSlot.prototype, 'name', {
get : function() {
var start = this.start;
var value = ((start - nulloDate) == 0) ?
' [Select a timeslot]' :
(start && moment.utc(start).isValid()) ?
moment.utc(start).format('ddd hh:mm a') : ' [Unknown]';
return value;
}
});

Validation on the Server for Data Integrity always
Validation on the Client for User Experience

View Level: Should you copy business rules to HTML?
vs
Model Level: Should the model drive the UI?

Separation of how you calculate the validation error from how you display it.

breeze.directives.validation.js
Install-Package Breeze.Angular.Directives

<input data-ng-model="vm.session.title" placeholder="Session title" data-z-validate />

//tell breeze not to validate when we attach a newly created entity to any manager
new breeze.ValidationOptions({ validateOnAttach: false }).setAsDefault();

app.config(['zDirectivesConfigProvider', function(cfg) {
cfg.zValidateTemplate = '<span class="invalid"><i class="icon-warning-sign"></i>%error%</span>';
}])

Saving State - How do we recover quickly?

Instal-Package angular.breeze.storagewip (ngzWip)

zStorage.init(manager);

function listenForStorageEvents() {
$rootScope.$on(config.events.storage.storeChanged, function ...
... config.events.storage.wipChanged ...
... config.events.storage.error ...
}

var exportData = entityManager.exportEntities();
$window.localStorage.setItem(key, exportData);

var importData = $window.localStorage.getItem(storageKey);
entityManager.importEntities(importedData);

eg. after loading lookups in prime method, we could call zStorage.save();
but also after query and saves that are successful

http://caniuse.com/#search=localstorage

Storing work in progress (zStorageWip)

zStorageWip.init(manager);

manager.entityChanged.subscribe(function(changeArgs) {
if (changeArgs.entityAction == breeze.EnityAction.propertyChanged) {
common.$broadcast(events.entitiesChanged, changeArgs);
}
});

function autoStoreWip(immediate) {
common.debouncedThrottle(controllerId, storeWipEntity, 1000, immediate);
}

function onEveryChange() {
$scope.$on(config.events.entitiesChanged, function(event,data) { autoStoreWip(); });
}


//Forget certain changes by removing them from the entity's originalValues
//This function becomes unnecessary if Breeze decides that unmapped properties are not recorded in originalValues
//We remove the properties we do not want to track
function interceptPropertyChange(changeArgs) {
var changedProp = changeArgs.args.propertyName;
if (changedProp === 'isPartial' || changedProp === 'isSpeaker') {
delete changeArgs.entity.entityAspect.originalValues[changedProp];
}
}

var importedEntity = this.zStorageWip.loadWipEntity(wipEntityKey);
if (importedEntity) {
importedEntity.entityAspect.validateEntity();
return $.when({ entity:importedEntity, key:wipEntityKey });
}

<li data-cc-wip wip="vm.wip" routes="vm.routes" changed-event="{{vm.wipChangedEvent}}" class="nlightblue"></li>

$scope.wipExists = function() { return !!$scope.wip.length; } //double bang will turn number into boolean

<div class="widget-content" data-ng-include="'/app/wip/widget.html'"> //double, single quote

<div class="widget-content referrer" data-ng-switch="!!vm.wip.length">
<div data-ng-switch-when="false">No work in progress is found</div>
<table data-ng-switch-when="true">
...
... {{item.date | date: 'MM/dd/yyyyy @ h:mma'}}
</table>
</div>

more: http://jpape.me/htmlstore - html5 web storage indexeddb and filesystem by craig shoemaker

 

Entity Framework in the Enterprise - Notes 

Categories: EF Notes

by Julie Lerman

UI - Service Layer - Bus Layer - Repository/Unit of Work - Data Layer - Database

EF should stay in the data layer.
Split your context in smaller bounded contexts.

Bounded DbContext

  • Inspired on "Domain-Driven Design by Eric Evans" (domaindrivendesign.org)
  • All your navigation properties get pulled into the model.
  • Transition between context by id or by object.
  • Entity with property that is not persisted in the database: public decimal LineTotal { get; set; } ... In map class add Ignore(t => t.LineTotal)
  • Do not include navigation in the context: In OnModelCreating add modelBuilder.Ignore<T>();
  • Make sure non related is included: In OnModelCreating add modelBuilder.Entity<T>();
  • Migrations and creations: Add one model that includes all of your tables and use this one.
  • Put each context in it's own project.
  • Put the mappings also in their separated project. eg. BaseDataLayer - CompanyDatabaseInitializers - CustomerServiceBoundedContext - DataLayerMappings - DomainClasses - ReturnsBoundedContext - SalesBoundedContext
  • Use EF powertools to visualize your context and see what will be pulled in.
  • And then cherry pick what you need (eg. probably do not need the relationships)

Repositories and Unit of Work

  • Encapsulate Redundant Data Access Code
  • GetCustomerById(cid), GetAllCustomers, GetCurrentCustomers, GetLocalCustomers, GetFilteredCustomers
  • RemoveCustomer, AddCustomer

Install-Package entityframework
Install-Package t4scaffolding

scaffold repository DomainClasses.Customer -DbContextType:SalesContext

Always use ctx.Customers.Find(id) cause it will not roundtrip when not needed.

DbSet.Add(root) - All elements State=Added - Insert for each element, even if pre-existing in db
DbSet.Attach(root) - All elements State=Unchanged - Any new records with missing FKs will throw
Context.Entry(root).State=EntityState - Context attaches full graph, all entities State=Unchanged, Root (only) set to specific state - Any new with missing FKs will throw

Disconnected Graph
Attaching to Context: all new -> DbSet.Add(customer)
Root new, existing unchanged: Entry(customer).State=Added
Editing: Entry(customer).State=Modified then Entry(*each item*).State=Modified
Root edited and added: DbSet.Add(customer) then Entry(*each non added*).State=*correct state*

Make objects track their own state:
IObjectWithState
enum State { Added, Unchanged, Modified, Deleted }

public abstract class Person:IObjectWithState
[NotMapped]
public State State { get; set;}

Repository depends on the value of client-side State
Developer using repository MUST set client-side State!

StateHelpers - EntityState ConvertState(State state)
ContextHelpers - ApplyStateChanges(this DbContext context)

Difference between long running and short running context (or implement two repos)

Let repositories share the same context (Unit of work)
Move save method to unit of work
CustomerRepository contains Unit of work that contains a context

ReferencesContext
Especially when reading data: _context.Customers.AsNoTracking();

A DbSet represents the collection of all entities in the context, or that can be queried from the database, of a given type.
DbSet object are created from a DbContext using the DbContext.Set method
A DbContext instance represents a combination of the unit of work and repository patterns such that it can be used to query a database and group together changes that will then be written back to the store as a unit. DbContext is conceptually similar to ObjectContext.

  • Why build a repository on top op EF? EF is a repository!
  • Should you return an IQueryable from a repository
  • How much abstraction and refactoring? There will always be more.

Automated Testing Overview

  • Unit Testing
  • Integration Testing
  • Interaction Testing
  • System Testing
  • User Interface Testing

1. Complete model with Seed method
2. Initialize Database for each integration test
3. Use a testing database that can get destroyed frequently

Test your data annotations: test for DbEntityValidationException

Fake Context & Fake Data
IDbSet<TEntity> : DbQuery<TEntity>, IDbSet<TEntity>, IQueryable<TEntity>, IEnumerable<TEntity>, IQueryable, IEnumerable where TEntity : class

(you can also use IObjectSet)
public abstract class MyFakeDbSet<T> : IDbSet<T> where T : class, new()
{
}

Create implementation to override the find method

IUoW needs IContext

SalesPromotionAccessor (to hide the context and wrap it with your unit of work)

Building Data-Centric Single Apps with Breeze - Notes 

Categories: Javascript Notes

by Brian Noyes (brian.noyes@solliance.net)
www.solliance.net

Server Side

  • BreezeController vs OData vs client enriching

Query Calling Pattern

  • Client > executeQuery(query) > Entity Manager > GET Metadata from Controller (first time) > GET Query the controller > Return Query Results

SaveChanges Calling Pattern

  • Client > saveChanges > Entity Manager > POST Modified Entity ChangeSet > Controller > Return Server Persisted Entities

RPC, CRUD, REST, ODATA Services

  • Breeze routing is action-based (contains an entire model) > by default using a WebActivator.PreApplicationStartMethod(...)
  • OData query parameters are turned into an expression tree that is executed against the return IQueryable by the query filter
  • SaveChanges takes a JObject bundle with a batch of entities.

Extend EFContextProvider to add custom code

  • BeginSaveEntity, BeginSaveEntities (Derived or Delegated)
_ContextProvider.BeforeSaveEntitiesDelegate = BeforeSaveEntities;
private Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(Dictionary<Type, List<EntityInfo> saveMap)
{
var validator = new ProductValidator();
foreach (var type in saveMap.Keys)
{
if (type == typeof(Product))
foreach (var productEntityInfo in saveMap[type])
{
validator.Validate((Product)productEntityInfo.Entity)
}
}
}

Working with OData Services

  • On client data.js is needed
  • Server needs to define Entity Data Model with same namespace as entity types namespace
  • Metadata returned from the server needs to include foreign key relation information
  • Need some changes to the way you setup Entity Data Model and return metadata from the server
public class ZzaODataService : DataService<ZzaEntities>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("Products", EntitySetRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
}

public static void RegisterRoutes(RouteCollection routes)
{
...
routes.IgnoreRoute("{resource}.svc/{*pathInfo}");
...
}

  • edmx > properties > Namespace: ZzaODataWeb (same project space as service)

app = {};
breeze.config.initializeAdapterInstance({dataService:"OData"});
em = new breeze.EntityManager("ZzaODataService.svc");

  • GET /ZzaODataService.svc/$metadata (returns xml)
  • GET /ZzaODataService.svc/Products
  • POST /ZzaODataService.svc/$batch (multi-part mime message)

Breeze Query Basics

app.em = new breeze.EntityManager("breeze/Zza");
breeze.EntityQuery.from("Products").where("Description","contains","bacon");
app.em.executeQuery(query).then(...).fail(...);

var p = new breeze.Predicate("Description","contains","bacon");
... .where(p);

var gteMay1 = new breeze.Predicate("OrderDate", "greaterThanOrEqual", moment("2013-05-01");
var lteMay31 = new breeze.Predicate("OrderDate", breeze.FilterQueryOp.LessThanOrEqual, moment("2013-05-31");
...
var predicate = breeze.Predicate.and(gteMay1, lteMay31, gt100);

... orderBy("Name");
... orderBy("TotalPrice, Order.OrderDate");
... orderBy("OrderDate desc").skip(currentPage() * pageSize).take(pageSize);

... orderBy("OrderDate desc").skip(currentPage() * pageSize).take(pageSize).inlineCount();

... select("LastName, Phone, State");
... from("OrderItems").where("Order.Customer.LastName","equals", queryInput()).select("Order.OrderDate, Product.Name, Quantity");
-> use Product_Name, Order_OrderDate to reference the projected elements.

... query.expand("Orders,Orders.OrderDetails,Orders.OrderDetails.Product"); //eagerloading

Breeze Query Advanced

Pre-fetching Metadata is needed when getting by id or creating.
... EntityManager.fetchMetadata().fail(...);

... EntityManager.fetchEntityByKey("Products", key).then(...);


public object Lookups()
{
var products = _ContextProvider.Context.Products.ToList();
...
return { products, productOptions };
}
breeze.EntityQuery.from("Lookups");
... data.results[0].products
... data.results[0].productOptions

public IQueryable<OrderItem> OrderItemsWithCouponCode(string couponCode, string customerClass)
{
...
}
var query = breeze.EntityQuery.from("OrderItemsWithCouponCode").withParameters({ couponCode:"XYZ", customerClass:"Gold"});

Server-Driven Queries (group by, sum, ...)
public IQueryable<object> TopCustomers()
{
var query = (from o in _ContextProvider.Context.Orders
group o by o.CustomerId into g
select new { Customer = g.FirstOrDefault().Customer.LastName, Total = g.Sum(o => o.ItemsTotal) }).OrderByDescending(a => a.Total);
return query;
}
... from("TopCustomers").take(10);

... requeryProducts.push(product)
... fromEntities(requeryProducts); //or by id that replaces the cache, you can also put a sigle entity

breeze.EntityQuery.from("Products").where(...)
... em.executeQueryLocally(query); //synchronous
query.using(breeze.FetchStrategy.FromLocalCache); //async with promise

EntityAspect: contains metadata and state information about the entity

  • breeze.NamingConvention.camelCase.setAsDefault(); //type and collections are pascal case, properties or camelcase

EntityManager.createEntity: creates instance and add to cache
newCustomer = function() {
var cust - em.createEntity("Customer", { id: breeze.core.getUuid() });
return cust;
}

EntityType.createEntity: reference from meta, entity from meta, create, add to cache
newCustomer = function() {
var metadataStore = em.metadataStore;
var custType = metadataStore.getEntityType("Customer");
var cust = custType.createEntity({ id: breeze.core.getUuid() });
em.addEntity(cust);
return cust;
}

var pendingStatus = em.executeQueryLocally(breeze.EntityQuery.from("OrderStatuses").where("name", "equals", "Pending"))[0];
order.orderStatusId(pendingStatus.id());
return order;

addToOrder = function(product) {
if (!Order()) order(zzaDataService.createNewOrder(customer()));
var orderItem = order().entityAspect.entityManager.createEntity("OrderItem");
orderItem.order(order());
orderItem.product(product);
orderItem.productSizeId(1);
orderItems.push(orderItem);
}

editingCustomer().entityAspect.rejectChanges();
em.rejectChanges();

//after accepting changes you will not be able to persist them !
... entityAspect.acceptChanges(); //should only be used when mocking data

customer.entityAspect.setDeleted();
customers.remove(customer);

Named Saves
zzaDataService.saveCustomers().fail(...)
...
var customers = em.getChanges("Customer");
return em.saveChanges(customers);
...
var saveOptions = new breeze.SaveOptions({ resourceName:"SaveOrder" });
var orders = [order];
return em.saveChanges(orders, saveOptions);
...
[HttpPost]
public SaveResult SaveOrder(JObject saveBundle)
{
return _ContextProvider.SaveChanges(saveBundle);
}

Working with Entities on the client

Entity States:

  • Unchanged - after being loaded by a query or after successful saveChanges
  • Modified - previously unchanged entity has a property change
  • Added - entity has been created and added to the cache, but not saved to back end
  • Deleted - previously unchanged entity is marked for deletion
  • Detached

Newly created entity that has not been added to the cache
Added entity that gets marked for deletion
Deleted entity after saveChanges is complete
Entities that were in the cache when EntityManager.clear is called
EntityManager.detachEntity called
EntityAspect.entityState
createEntity, setDeleted, rejectChanges, acceptChanges
EntityAspect.setModified, EntityAspect.setUnchanged

Extending Entities: Modify the EntityType in the Breeze metadataStore
Saved when exported, but not persisted to the server.

addEntityExtensions = function () {
var store = em.metadataStore;
store.registerEntityTypeCtor("Customer", Customer)
}
var Customer = function() {
this.firstName = ko.observable(''); //solves race condition
this.lastName = ko.observable('');
this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this);
}
OR
Customer.prototype.getFullName = function() {
return this.firstName() + " " + this.lastName();
}

Handling Entity Property Changes

  • Breeze raises its own (observable agnostic) property change events
  • EntityAspect.propertyChanged.subscribe returns a subscription token
  • Avoid memory leaks by EntityAspect.propertyChanged.unsubscribe(token)
tokens = {};
var token = addingCustomer().entityAspect.propertyChanged.subscribe(function()arg {
logger.info("Customer:" + arg.entity.fullName() + "property " + arg.propertyName + "changed value" + arg.oldValue + "into" + arg.newValue);
})
tokens[addingCustomer().id] = token;
... unsubscribe(tokens[customers()[i].id]) ...

EntityManager.entityChanged.subscribe (eg. undo)
-> entityAction, entity, args

Exporting and importing cached entities
Using an entityChangedHandler to make sure changes are saved locally for when user would close browser before saving
var bundle = em.exportEntities(em.getChanges());
window.localStorage.setItem("magickey", bundle);
...
var bundle = window.localStorage.getItem("magickey");
if (bundle) em.importEntities(bundle);
...
clear local storage on save

Validation

  • Returns HTTP 403 Forbidden status code when validation errors
  • Collection of ValidationError objects per entity (propertyName, property, errorMessage, context, isServerError, key, validator)
  • Automatically adds type, required and length validation
  • Configurable - EntityManager.validationProperties
saveError = function (error) {
if (error.entityErrors) {
showValidationErrors(error.entityErrors);
}
else {
logger.error(error.message, "Error saving data");
}
}
showValidationErrors = function (errors) {
var errorMessage = "";
errors.map(function (e) {
if (errorMessage.length > 0) errorMessage += ", ";
errorMessage += e.errorMessage;
});
logger.error(errorMessage, "Validation Errors");
}

Data Annotations (System.ComponentModel.DataAnnotations)
[Required], [StringLength(50)], Range, RegularExpresssion, Compare
[DataType(DataType.Currency)], Date, Time, DateTime, PostalCode, ...
Phone, [EmailAddress], CreditCard, Url

function initValidation(em) {
var store = em.metadataStore;
var userType = store.getEntityType("User");
var phoneProp = userType.getProperty("phone");
phoneProp.validators.push(breeze.Validator.phone());
}

var userKeyValidator = breeze.Validator.makeRegExpValidator(
"userKeyVal",
/^[A-Z] ... regex ... $/,
"%displayName% '%value%' is not a valid GUID");
);

if (validateUser(editingUser()) { ... saveChanges ... }
validateUser = function(user) {
if (!user.entityAspect.validateEnitity()) {
var errors = user.entityAspect.getValidationErrors();
showValidationErrors(errors);
return false;
}
return true;
}


function isValidScoreRange(value, context) {
return value > context.minValue && value <= context.maxValue;
}
var scoreRangeValidator = new breeze.Validator("scoreRangeValidator", isValidScoreRange, { messageTemplate: '...' });
userType.getProperty("score").validators.push(scoreRangeValidator);
function rangeValidatorFactory(context) {
return new breeze.Validator("rangeValidator", isValidRange,
{
minValue: context.minValue,
maxValue: context.maxValue,
messageTemplate: '... %minValue% ... %maxValue% ...'
OR messageTemplate: breeze.core.formatString("'... %1 ... %2'", context.minValue, context.maxValue)
}
);
}
userType.getProperty("score").validators.push(rangeValidatorFactory({ minValue:1, maxValue:100 }));

//register to allow export and imports
breeze.Validator.register(userKeyValidator);
breeze.validator.registerFactory(rangeValidatorFactory, "rangeValidator");


app.em.validationErrorChanged.subscribe(function(args) {
if (args.added) ...
}


editSubscriptionToken = editingUser().entityAspect.validationErrorsChanged.subscribe(...);
... unsubscribe ...


Customer Server Validation

  • Inherit from ValidationAttribute
  • CustomValidatorAttribute
  • Custom business logic (EntityErrorsException from BreezeController BeginSaveEntity)
  • [CustomValidation(typeof(UserValidationRules), "ValidateEmail")]
public static class UserValidationRules
{
public static ValidationResult ValidateEmail(string value, ValidationContext context)
{
if (!value.EndsWith("...") return new ValidationResult("...");
return ValidationResult.Success;
}
}

private bool BeforeSaveEntity(EntityInfo entityInfo)
{
User user = entityInfo.Entity as User;
if (user != null)
{
if (!user.CreditCard.StartsWith("5"))
{
throw new EntityErrorsException(new List<EntityErrors>)
{
new EntityError
{
EntityTypeName = user.GetType().ToString(),
ErrorMessage = "We only accept Mastercard",
PropertyName = "CreditCard",
ErrorName = "CreditCardValidationError",
KeyValues = new object[] { user.Id }
}
}
}
}
return true;
}

Win 7 setup outbound firewall rules 

Categories: Security Windows

Enable Notifications

  • Local Group Policy Editor (gpedit.msc) > Computer Configuration > Windows Settings > Security Settings > Local Policies > Audit Policy > Audit object access on Failure
  • Event Viewer (eventvwr.msc) > Windows Logs > Security
  • Local Security Policy (secpol.msc) > Advanced Audit Policy Configuration > Object Access > Disable Audit Handle Manupulation

Protocol Numbers

  • 1: ICMPv4
  • 2: IGMP
  • 6: TCP
  • 17: UDP
  • 41: IPv6
  • 43: IPv6-Route
  • 44: IPv6-Frag
  • 47: GRE
  • 58: ICMPv6
  • 59: IPv6-NoNxt
  • 60: IPv6-Opts
  • 112: VRRP
  • 113: PGM
  • 115: L2TP

Before Win 7 this was needed:

  • auditpol /set /SubCategory:"MPSSVC Rule-Level Policy Change","Filtering Platform Policy Change","IPsec Main Mode","IPsec Quick Mode","IPsec Extended Mode","IPsec Driver","Other System Events","Filtering Platform Packet Drop","Filtering Platform Connection" /success:disable /failure:enable
  • net stop MPSSVC
  • net start MPSVC

OAuth 2.0 Vocabulary 

Categories: Security

by Ryan Boyd

Why not username & password?

  • Trust
  • Decreased user sensitivity to phising
  • Expand access & risk
  • Limited reliability
  • Revocation challenges
  • Passwords become required
  • Difficulty implementing stronger authentication

Authentication & Authorization

  • Authentication: verify the identity of the user
  • Federated Authentication: rely on other services to do the authentication (openID connect on top of OAuth 2.0)
  • Authorization: right to perform some action
  • Delegated authorization: granting access to another person or application to perform actions on your behalf

Roles

  • Resource server: server containing the protected data
  • Resource owner: user that has ability to grant access to the server
  • Client: application making api requests to perform actions on server
  • Authorization server: gets consent from resource owner and issues access tokens to clients for accessing protected resources
Page 16 of 43 << < 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 40 > >>