DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Curious about the future of data-driven systems? Join our Data Engineering roundtable and learn how to build scalable data platforms.

Data Engineering: The industry has come a long way from organizing unstructured data to adopting today's modern data pipelines. See how.

Threat Detection: Learn core practices for managing security risks and vulnerabilities in your organization — don't regret those threats!

Managing API integrations: Assess your use case and needs — plus learn patterns for the design, build, and maintenance of your integrations.

Avatar

Rahul Rajat Singh

Technical Architect at HFS

Pune, IN

Joined Jun 2014

About

My name is Rahul Rajat Singh, this is my personal blog focused on C#, ASP.NET, ASP.NET MVC, JavaScipt/JavaScript frameworks, SQL Server, Microsoft Technologies and Software Architecture. I’m a CodeProject MVP (2013, 2014). I am in software development since 2005. I am working on developing Information Systems, e-commerce/e-governance Portals and Data driven websites using ASP.NET, ASP.NET MVC, SQL Server, C# and JavaScript. My interests involves Programming, Website development, Project Management, Software Architecture and Learning/Teaching subjects related to Computer Science, Information Systems and Software Architecture. twitter: @rahulrajatsingh ‏

Stats

Reputation: 332
Pageviews: 434.7K
Articles: 6
Comments: 0
  • Articles

Articles

article thumbnail
Tutorial on Handling Multiple ResultSets and Multiple Mapping Using Dapper
In this article, we will look at how to use Dapper to read multiple ResultSets from the database in a single database call.
Updated September 20, 2018
· 42,032 Views · 3 Likes
article thumbnail
An Absolute Beginner's Tutorial on Middleware in ASP.NET Core/MVC
Let's see how middleware plays an important part in the request-response pipeline and how we can write and plug in our custom middleware.
September 18, 2018
· 33,365 Views · 2 Likes
article thumbnail
Understanding Retry Pattern With Exponential Back-Off and Circuit Breaker Pattern
Continuing reading for an in-depth discussion about the retry design pattern and its relation to the circuit breaker pattern.
October 10, 2016
· 178,139 Views · 34 Likes
article thumbnail
BackBone Tutorial - Part 7: Understanding Backbone.js Routes and History
in this article, we will try to look at routes in backbone.js. we will try to understand how routes can be useful in a large scale single page applications and how we can use routes to perform action based on requested url. background we have been using web application for more than 2 decades now. this has made us tuned to some of the functionalities that the websites provide. one such functionality is to be able to copy the url and use it for the viewing the exact application area that we were viewing before. another example is the use of browser navigation buttons to navigate back and forth the pages. when we create single page applications, there is only one page being rendered on the screen. there is no separate url for each page. the browser is not loading the separate pages for separate screens. so how can we still perform the above mentioned operations even with a single page application. the answer is backbone routes. link to complete series: backbone tutorial – part 1: introduction to backbone.js [ ^ ] backbone tutorial – part 2: understanding the basics of backbone models [ ^ ] backbone tutorial – part 3: more about backbone models [ ^ ] backbone tutorial – part 4: crud operations on backbonejs models using http rest service [ ^ ] backbone tutorial – part 5: understanding backbone.js collections [ ^ ] backbone tutorial – part 6: understanding backbone.js views [ ^ ] backbone tutorial – part 7: understanding backbone.js routes and history [ ^ ] using the code backbone routes and history provides us the mechanism by which we can copy the urls and use them to reach the exact view. it also enables us to use browser navigation with single page applications. actually routes facilitate the possibility of having deep copied urls and history provides the possibility of using the browser navigation. life without router let us try to create a simple application that is not using the router. lets create three simple views and these views will be rendered in the same area on our application based on user selection. let create 3 very simple views. var view1 = backbone.view.extend({ initialize: function() { this.render(); }, render: function() { this.$el.html(this.model.get('message') + " from the view 1"); return this; } }); var view2 = backbone.view.extend({ initialize: function() { this.render(); }, render: function() { this.$el.html(this.model.get('message') + " from the view 2"); return this; } }); var view3 = backbone.view.extend({ initialize: function() { this.render(); }, render: function() { this.$el.html(this.model.get('message') + " from the view 3"); return this; } }); now we need a view that will contain the view and render it whenever the user makes a choice on the screen. var containerview = backbone.view.extend({ mychildview: null, render: function() { this.$el.html("greeting area"); this.$el.append(this.mychildview.$el); return this; } }); var containerview = backbone.view.extend({ mychildview: null, render: function() { this.$el.html("greeting area"); this.$el.append(this.mychildview.$el); return this; } }); now we need a view that will contain the view and render it whenever the user makes a choice on the screen. now lets create a simple div on the ui which will be used as elto this containerview. we will then position three buttons on the ui which will let the user to change the view. below code shows the application setup that is creating the container view and the functions that will get invoked when the user selects the view from screen. var greeting = new greetmodel({ message: "hello world" }); var container = new containerview({ el: $("#appcontainer"), model: greeting }); var view1 = null; var view2 = null; var view3 = null; function showview1() { if (view1 == null) { view1 = new view1({ model: greeting }); } container.mychildview = view1; container.render(); } function showview2() { if (view2 == null) { view2 = new view2({ model: greeting }); } container.mychildview = view2; container.render(); } function showview3() { if (view3 == null) { view3 = new view3({ model: greeting }); } container.mychildview = view3; container.render(); } now lets run the application and see the results. when we click on the buttons we can see that the actual view is getting changes but the url is not getting changes. that would mean that there is no way, i can copy a url and directly go to any view. also, the second thing to note here is that if we press the browser back button, the application will go away(since its still on the same single page from the browser’s perspective). note: please download and run the sample code to see this in action. hello backbone routes now the above problem can very easily be solved using backbone routesand history. so lets try to first look at what are backbone routes. backbone routes are simple objects that are handle the incoming route value from the url and the invoke any function. lets create a very simple route class for our application. var myrouter = backbone.router.extend({ }); in our route class we will have to define the routes that our application will support and how we want to handle them. so first lets create a simple route where only the url is present. this usually is the starting page of our application. for our application lets just open view1 whenever nothing is present in the route. then if the request is for any specific view we will simply invoke the function which will take care of rendering the appropriate view. var myrouter = backbone.router.extend({ greeting: null, container: null, view1: null, view2: null, view3: null, initialize: function() { this.greeting = new greetmodel({ message: "hello world" }); this.container = new containerview({ el: $("#rappcontainer"), model: this.greeting }); }, routes: { "": "handleroute1", "view1": "handleroute1", "view2": "handleroute2", "view3": "handleroute3" }, handleroute1: function () { if (this.view1 == null) { this.view1 = new view1({ model: this.greeting }); } this.container.mychildview = this.view1; this.container.render(); }, handleroute2: function () { if (this.view2 == null) { this.view2 = new view2({ model: this.greeting }); } this.container.mychildview = this.view2; this.container.render(); }, handleroute3: function () { if (this.view3 == null) { this.view3 = new view3({ model: this.greeting }); } this.container.mychildview = this.view3; this.container.render(); } }); now this route class contains the complete logic of handling the url requests and rendering the view accordingly. not only this, we can see that the code which was written in a global scope earlier i.e. the controller and view creation all that is put inside the route now. this would also mean that routes not only provide us deep copyable urls but also could provide more options to have better structured code(since we can have multiple route classes and each route class can handle all the respective views for the defined routes). backbone history and instantiating routes backbone history is a global router that will keep track of the history and let us enable the routing in the application. to instantiate a route and start tracking the navigation history, we need to simply create the router class and call backbone.history.start for let the backbone start listening to routes and manage history. $(document).ready(function () { router = new myrouter(); backbone.history.start(); }) invoking and requesting routes a route can either be invoked from the other parts of the application or it can simply be requested by the user. invoking route: application wants to navigate to a specific route (this can be done by navigating to a route by calling the navigate function: router.navigate('view1'); route request: user enters the fully qualified url (this will work seamlessly) let us run the application and see the result. passing parameters in the routes we can also pass parameters in the route. lets us try to create a new route where the user will request for a view in a parameterized manner. parameters can be defined as “ route/:param” var myrouter = backbone.router.extend({ greeting: null, container: null, view1: null, view2: null, view3: null, initialize: function () { this.greeting = new greetmodel({ message: "hello world" }); this.container = new containerview({ el: $("#rappcontainer"), model: this.greeting }); }, routes: { "": "handleroute1", "view/:viewid": "handlerouteall" }, handlerouteall: function (viewid) { if (viewid == 1) { this.handleroute1(); } else if (viewid == 2) { this.handleroute2(); } else if (viewid == 3) { this.handleroute3(); } }, handleroute1: function () { if (this.view1 == null) { this.view1 = new view1({ model: this.greeting }); } this.container.mychildview = this.view1; this.container.render(); }, handleroute2: function () { if (this.view2 == null) { this.view2 = new view2({ model: this.greeting }); } this.container.mychildview = this.view2; this.container.render(); }, handleroute3: function () { if (this.view3 == null) { this.view3 = new view3({ model: this.greeting }); } this.container.mychildview = this.view3; this.container.render(); } }); the above route can be invoked by passing view/2 as url. the viewid passed to the router will be 2. having optional parameters in routes we can also pass optional parameters in the routes, lets try to pass a simple parameter in the above defined route and see how it works. optional parameters can be defined as “ route(/:param)“. var myrouter = backbone.router.extend({ routes: { "": "handleroute1", "view1": "handleroute1", "view2": "handleroute2", "view3": "handleroute3", "view/:viewid(/:msg)": "handlerouteall" }, handlerouteall: function (viewid, msg) { if (msg) { alert(msg); } } }); in the above code, if we pass the second parameter i.e. view/2/test, the alert will be shown else not. note: the route definition can also contain complex regex based patterns if we need one route to handle multiple urls based on some regular expression. point of interest in this article we saw backbone.js routes. we saw how routes enable us to create bookmarkable urls and will let the user request a view based on url. we also looked at how we can use browser navigation by using backbone history. this has been written from a beginner’s perspective. i hope this has been informative. download sample code for this article: backboneroutessample
September 18, 2014
· 9,914 Views
article thumbnail
BackBone Tutorial - Part 5: Understanding Backbone.js Collections
In this article we will discuss about Backbone.js collections. We will see how we can use collections to manipulate a group of models and how we can use restul API to easily fetch and save collections. Background Every application needs to create a collection of models which can be ordered, iterated and perhaps sorted and searched when a need arises. Keeping this in mind, Backbone also comes with a collection type which makes dealing with collection of models fairly easy and straight forward. Link to complete series: BackBone Tutorial – Part 1: Introduction to Backbone.Js BackBone Tutorial – Part 2: Understanding the basics of Backbone Models BackBone Tutorial – Part 3: More about Backbone Models BackBone Tutorial – Part 4: CRUD Operations on BackboneJs Models using HTTP REST Service BackBone Tutorial – Part 5: Understanding Backbone.js Collections[^] BackBone Tutorial – Part 6: Understanding Backbone.js Views[^] BackBone Tutorial – Part 7: Understanding Backbone.js Routes and History[^] Using the code Let us start looking at the backbone collections in details. Creating a collection Creating a backbone collection is similar to creating a model. We just need to extend the backbone’s collection class to create our own collection. Let us continue working with the same example where we created a Book model and let's try to create a simple BooksCollection. var BooksCollection = Backbone.Collection.extend({ }); This collection will hold the Book model we have created in our previous articles. var Book = Backbone.Model.extend({ defaults: { ID: "", BookName: "" }, idAttribute: "ID", urlRoot: 'http://localhost:51377/api/Books' }); Specifying the model for a collection To specify which model this collection should hold, we need to specify/override the model property of the collection class. var BooksCollection = Backbone.Collection.extend({ model: Book, }); Once we specify the model property of a collection what will happen internally is that whenever we create this collection, internally it will create an array of the specified models. Then all the operations on this collection object will result in the actual operations on that array. Instantiating a collection A collection can be instantiated by using the new keyword. We can create an empty collection and then add the model objects to it later or we can pass a few model objects in the collection while creating it. // Lets create an empty collection var collection1 = new BooksCollection(); //Lets create a pre-populated collection var book1 = new Book({ ID: 1, BookName: "Book 1" }); var book2 = new Book({ ID: 2, BookName: "Book 2" }); var collection2 = new BooksCollection([book1, book2]); Adding models to collection To add an item to a collection, we can use the add method on the collection. The important thing to notice here is that if the item with the same id exist in the collection, the add will simply be ignored. var book3 = new Book({ ID: 3, BookName: "Book 3" }); collection2.add(book3); Now there might be a scenario where we actually want to update an existing added model in a collection. If that is the case, then we need to pass the {merge:true} option in the add function. var book3 = new Book({ ID: 3, BookName: "Book 3" }); collection2.add(book3); var book3_changed = new Book({ ID: 3, BookName: "Changed Model" }); collection2.add(book3_changed, { merge: true }); Another important point to consider here is that the collection keep a shallow copy of the actual models. So if we change a model attribute after adding it to a collection, the attribute value will also get changed inside the collection. Also, if we want to add multiple models, we can do that by passing the model array in the add method. var book4 = new Book({ ID: 4, BookName: "Book 4" }); var book5 = new Book({ ID: 5, BookName: "Book 5" }); collection2.add([book4, book5]); It is also possible to add the model at a specific index in the collection. To do this we need to pass the {at:location} in the add options. var book0 = new Book({ ID: 0, BookName: "Book 0" }); collection2.add(book0, {at:0}); Note: push and unshift function can also be used to add models to collection. Removing models from collection To remove the model from the collection, we just need to call the remove method on the collection. The remove method simply removes this model from the collection. collection2.remove(book0); Also, if we want to empty the model, we can call the reset method on the collection. collection1.reset(); It is also possible to reset a collection and populate it with new models by passing an array of models in the reset function. collection2.reset([book4, book5]); // this will reset the collection and add book4 and book5 into it Note: pop and shift function can also be used to remove model from collection. Finding the number of items in collection The total number of items in a collection can be found using the length property. var collection2 = new BooksCollection([book1, book2]); console.log(collection2.length); // prints 2 Retrieving models from collection To retrieve a model from a specific location, we can use the at function by passing a 0 based index. var bookRecieved = collection2.at(3); Alternatively, to get the index of a known model in the collection, we can use the indexOf method. var index = collection2.indexOf(bookRecieved); We can also retreive a model from a collection if we know its id or cid. this can be done by using the get function. var bookFetchedbyId = collection2.get(2); // get the book with ID=2 var bookFetchedbyCid = collection2.get("c3"); // get the book with cid=c3 If we want to iterate through all the models in a collection, we can simply use the classic for loop or the each function provided by collections which is very similar to the foreach loop of underscore.js. for (var i = 0; i < collection2.length; ++i) { console.log(collection2.at(i).get("BookName")); } collection2.each(function (item, index, all) { console.log(item.get("BookName")); }); Listening to collection events Backbone collection raises events whenever an item is added removed to updated in the collection. We can subscribe to these events by listening to add, remove and change event respectively. Let us subscribe to these events in our model to see how this can be done. var BooksCollection = Backbone.Collection.extend({ model: Book, initialize: function () { // This will be called when an item is added. pushed or unshifted this.on('add', function(model) { console.log('something got added'); }); // This will be called when an item is removed, popped or shifted this.on('remove', function(model) { console.log('something got removed'); }); // This will be called when an item is updated this.on('change', function(model) { console.log('something got changed'); }); }, }); The set function The set function can be used to update all the items in a model. If we use set function, it will check for all the existing models and the models being passed in set. If any new model is found in the models being passed, it will be added. If some are not present in the new models list, they will be removed. If there are same models, they will be updated. var collection3 = new BooksCollection(); collection3.add(book1); collection3.add(book2); collection3.add(book3); collection3.set([book1, { ID: 3, BookName: "test sort"}, book5]); The above shown set function will call remove for book2, change for book3 and add for book5. Sorting a collection Backbone keeps all the models in the collection in a sorted order. We can call the sort function to forcefully sort it again but the models are always stored in sorted order. By default these items are sorted in the order they are added to the collection. But we can customize this sorting behavior by providing a simple comparator to our collection. var BooksCollection = Backbone.Collection.extend({ model: Book, comparator: function (model) { return model.get("ID"); }, }); What this comparator does is that it overrides the default sorting behavior by specifying the attribute that should be used for sorting. We can even used a custom expression in this comparator too. Fetch collection using HTTP REST service To be able to fetch the collection from the server, we need to specify the url for the api that returns the collection. var BooksCollection = Backbone.Collection.extend({ model: Book, url: "http://localhost:51377/api/Books", }); Now to fetch the collection from the server, lets call the fetch function. var collection4 = new BooksCollection(); collection4.fetch(); Save collection using HTTP REST service Lets see how we can save the items of a collection on the server. var collection4 = new BooksCollection(); collection4.fetch({ success: function (collection4, response) { // fetch successful, lets iterate and update the values here collection4.each(function (item, index, all) { item.set("BookName", item.get("BookName") + "_updated"); // lets update all book names here item.save(); }); } }); In the above code we are calling save on each model object. this can be improved by either overriding the sync function on a collection or perhaps creating a wrapper model for collection and saving the data using that. Note: The web api code for can be downloaded from the previous article of the series. Point of interest In this article we have discusses about the backbone collections. This has been written from a beginner’s perspective. I hope this has been informative. Download sample code for this article: backboneSample
September 5, 2014
· 32,239 Views · 1 Like
article thumbnail
BackBone Tutorial - Part 4: CRUD Operations on BackboneJs Models using HTTP REST Service
In this article we will discuss how we can perform CRUD operations on a backbone model using a REST based HTTP service. Background Earlier we have discussed about the benefits of using backbone.js and we also looked at the backbone models. Link to complete series: BackBone Tutorial – Part 1: Introduction to Backbone.Js BackBone Tutorial – Part 2: Understanding the basics of Backbone Models BackBone Tutorial – Part 3: More about Backbone Models BackBone Tutorial – Part 4: CRUD Operations on BackboneJs Models using HTTP REST Service[^] BackBone Tutorial – Part 5: Understanding Backbone.js Collections[^] BackBone Tutorial – Part 6: Understanding Backbone.js Views[^] BackBone Tutorial – Part 7: Understanding Backbone.js Routes and History[^] In this article we will look at performing the CRUD operations on backbone models using a REST based web service. Using the code The first thing we will do is that we will create a simple REST based web api that can be used to save the data on the server using our simple backbone application. For this I have created a simple database with a single table as: The ID field is configured to auto increment and this is the primary key of the table. so while creating a new model we don’t have to provide this to the server. Now on top of this model, I have written a simple ASP.NET web api that will provide us the RESTful api. This API is configured to run on my local machine at: http://localhost:51377/. The API details are as follows: Create: POST http://localhost:51377/api/values Read: GET http://localhost:51377/api/values/{id} Update: PUT http://localhost:51377/api/values/{id} Delete: DELETE http://localhost:51377/api/values/{id} Once we have the API running, we can start working on our backbone model. We had create the backbone model in our previous article as: var Book = Backbone.Model.extend({ defaults: { ID: "", BookName: "" }, idAttribute: "ID", initialize: function () { console.log('Book has been initialized'); this.on("invalid", function (model, error) { console.log("Houston, we have a problem: " + error) }); }, constructor: function (attributes, options) { console.log('Book\'s constructor had been called'); Backbone.Model.apply(this, arguments); }, validate: function (attr) { if (!attr.BookName) { return "Invalid BookName supplied." } } }); The backbone models inherently supports saving on the server using a restful web api. To save the model using a HTTP REST service, we need to specify the urlRoot in the backbone model. To actually save the model, we can call the save on the backbone model.The save method will trigger the validations and if the validations are successful, it will try to identify the action to be performed i.e. create or update and based on that action, it will use urlRoot and call the appropriate REST API to perform the operation. Let us specify the URL root to enable this model to use our web api service. var Book = Backbone.Model.extend({ defaults: { ID: "", BookName: "" }, idAttribute: "ID", initialize: function () { console.log('Book has been initialized'); this.on("invalid", function (model, error) { console.log("Houston, we have a problem: " + error) }); }, constructor: function (attributes, options) { console.log('Book\'s constructor had been called'); Backbone.Model.apply(this, arguments); }, validate: function (attr) { if (!attr.BookName) { return "Invalid BookName supplied." } }, urlRoot: 'http://localhost:51377/api/Books' }); Now let us try to perform CRUD operations on this model. Create To create a new entity on the server, we need to populate the non identity fields in the model (other than ID in this case) and then call the Save method on the model. // Lets perform a create operation [CREATE] var book = new Book({ BookName: "Backbone Book 43" }); book.save({}, { success: function (model, respose, options) { console.log("The model has been saved to the server"); }, error: function (model, xhr, options) { console.log("Something went wrong while saving the model"); } }); Read To read a single book entity, we need to create the book entity with the identity attribute populated, i.e., the ID of the book we want to read. Then we need to call the fetch method on the model object. // Now let us try to retrieve a book [READ] var book1 = new Book({ ID: 40 }); book1.fetch({ success: function (bookResponse) { console.log("Found the book: " + bookResponse.get("BookName")); } }); Update Now let’s say we want to update the name of the book retrieved in the earlier fetch call. All we need to do is set the attributes we need to update and call the save method again. // Lets try to update a book [UPDATE] var book1 = new Book({ ID: 40 }); book1.fetch({ success: function (bookResponse) { console.log("Found the book: " + bookResponse.get("BookName")); // Let us update this retreived book now (doing it in the callback) [UPDATE] bookResponse.set("BookName", bookResponse.get("BookName") + "_updated"); bookResponse.save({}, { success: function (model, respose, options) { console.log("The model has been updated to the server"); }, error: function (model, xhr, options) { console.log("Something went wrong while updating the model"); } }); } }); Delete Now to delete a Model, we just need to call the destroy method of the model object. // Let us delete the model with id 13 [DELETE] var book2 = new Book({ ID: 40 }); book2.destroy({ success: function (model, respose, options) { console.log("The model has deleted the server"); }, error: function (model, xhr, options) { console.log("Something went wrong while deleting the model"); } }); Custom URLs to perform CRUD operation on models There are few scenarios where we might want to have provide custom URLs for the individual operations. This can be achieved by overriding the sync function and providing custom URL for each action. Let us create one more model BookEx to see how this can be done. var BookEx = Backbone.Model.extend({ defaults: { ID: "", BookName: "" }, idAttribute: "ID", // Lets create function which will return the custom URL based on the method type getCustomUrl: function (method) { switch (method) { case 'read': return 'http://localhost:51377/api/Books/' + this.id; break; case 'create': return 'http://localhost:51377/api/Books'; break; case 'update': return 'http://localhost:51377/api/Books/' + this.id; break; case 'delete': return 'http://localhost:51377/api/Books/' + this.id; break; } }, // Now lets override the sync function to use our custom URLs sync: function (method, model, options) { options || (options = {}); options.url = this.getCustomUrl(method.toLowerCase()); // Lets notify backbone to use our URLs and do follow default course return Backbone.sync.apply(this, arguments); } }); Now we can perform the CRUD operations on this model in the same way as we did for the previous model. Point of interest In this article we have looked at how to perform CRUD operations on backbone models using HTTP based REST service. This has been written from a beginner’s perspective. I hope this has been informative. Download sample Web API code: WebAPISample Download sample backbone app code: backboneSample
August 18, 2014
· 16,671 Views

User has been successfully modified

Failed to modify user

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: