Overview
Vidly is a video rental store web application built with ASP.NET MVC 5 that demonstrates core MVC architectural patterns including routing, controllers, models, view models, and Razor views.
Key Features
- Full CRUD Operations — Create, read, update, and delete movies
- Custom Attribute Routing — Filter movies by release date with constraint validation
- View Models — Composed data objects for strongly-typed view rendering
- Data Validation — Data annotation-based model validation
- Thread-Safe Data Store — Concurrent access via lock-based synchronization
- Repository Pattern — Decoupled data access with interface-based design
- Dependency Injection Ready — Constructor injection in controllers
- 33 Business Services — Rental, pricing, loyalty, analytics, recommendations, and more
- Comprehensive Test Suite — Models, controllers, services, and edge cases
Tech Stack
| Component | Technology |
|---|---|
| Framework | ASP.NET MVC 5.2.3 |
| Runtime | .NET Framework 4.5.2 |
| View Engine | Razor |
| CSS | Bootstrap 3 (Lumen theme) |
| JavaScript | jQuery 1.10.2 |
| Testing | MSTest + Coverlet |
| CI/CD | GitHub Actions |
Installation
Prerequisites
- Visual Studio 2017+ (or VS Code with C# extension)
- .NET Framework 4.5.2+ runtime and targeting pack
- NuGet package manager
Clone & Setup
git clone https://github.com/sauravbhattacharya001/Vidly.git
cd Vidly
Restore Dependencies
In Visual Studio:
Build → Restore NuGet Packages
Or via CLI:
nuget restore Vidly.sln
Run
Press F5 in Visual Studio to launch with IIS Express. The application starts at http://localhost:51355/.
Quick Start
After launching the application:
- Navigate to
/moviesto see the movie catalog - Click Create New to add a movie (name + optional release date)
- Edit or delete movies from the listing page
- Visit
/movies/randomfor a random movie recommendation - Try
/movies/released/2024/01to filter by release date
Project Structure
Design Patterns
🏗️ Repository Pattern
Data access is abstracted behind IRepository<T> and IMovieRepository interfaces. The InMemoryMovieRepository provides a thread-safe implementation using ConcurrentDictionary with additional locking for atomic operations.
💉 Dependency Injection
MoviesController uses constructor injection, accepting an IMovieRepository. The parameterless constructor provides a default in-memory implementation, while tests inject mocks/fakes for isolation.
📦 View Model Pattern
RandomMovieViewModel composes a Movie with a list of Customer objects, enabling the view to render data from multiple domain entities without coupling to the models directly.
🔒 Thread Safety
The in-memory repository uses lock statements for operations like Add, Update, and Remove that need atomicity (e.g., incrementing the ID counter). Read operations are lock-free via ConcurrentDictionary.
Models
Movie
| Property | Type | Validation |
|---|---|---|
| Id | int | Auto-assigned |
| Name | string | Required, max 255 chars |
| ReleaseDate | DateTime? | Optional |
Customer
| Property | Type | Validation |
|---|---|---|
| Id | int | Auto-assigned |
| Name | string | Required, max 255 chars |
RandomMovieViewModel
| Property | Type | Description |
|---|---|---|
| Movie | Movie | The randomly selected movie |
| Customers | List<Customer> | Associated customers |
Routes
| Method | Route | Description |
|---|---|---|
| GET | / | Home page |
| GET | /movies | Movie listing (pagination + sorting) |
| GET | /movies/random | Random movie showcase |
| GET | /movies/create | New movie form |
| POST | /movies/create | Submit new movie |
| GET | /movies/edit/{id} | Edit movie form |
| POST | /movies/edit/{id} | Submit movie edits |
| POST | /movies/delete/{id} | Delete a movie |
| GET | /movies/released/{year}/{month} | Filter by release date |
URL Parameters
| Parameter | Type | Description |
|---|---|---|
pageIndex | int | Page number (default: 1) |
sortBy | string | Name (default) or Id |
year | int | Release year (1888–2100) |
month | int | Release month (01–12) |
Controllers
MoviesController
Handles all movie CRUD operations. Uses constructor injection with IMovieRepository.
public class MoviesController : Controller
{
private readonly IMovieRepository _movieRepository;
// Default: uses InMemoryMovieRepository
public MoviesController() : this(new InMemoryMovieRepository()) { }
// DI-ready: accepts any IMovieRepository
public MoviesController(IMovieRepository movieRepository)
{
_movieRepository = movieRepository
?? throw new ArgumentNullException(nameof(movieRepository));
}
}
HomeController
Serves the landing page, About, and Contact views. Standard MVC controller with no custom logic.
Repositories
Interface Hierarchy
Thread Safety
The InMemoryMovieRepository uses a two-layer approach:
ConcurrentDictionary<int, Movie>for lock-free readslock(_lock)for write operations requiring atomicity (ID generation, add, update, remove)
Testing
Running Tests
# Restore and run
dotnet restore Vidly.Tests/Vidly.Tests.csproj
dotnet test Vidly.Tests/Vidly.Tests.csproj
# With coverage
dotnet test Vidly.Tests/Vidly.Tests.csproj --collect:"XPlat Code Coverage"
Test Suite (2,389 Tests across 59 Files)
| Category | Coverage |
|---|---|
| Model & ViewModel Tests | Validation, required fields, string length, defaults, composition |
| Controller Tests | All 10+ controllers: routing, authorization, error handling, edge cases |
| Service Tests | All 33 services: business logic, boundary conditions, error paths |
| Repository Tests | In-memory repositories: CRUD, thread safety, search, pagination |
| Security Tests | Export safety, rate limiting, anti-forgery, input validation |
Coverage Reports
Coverage reports are generated in Cobertura XML format and uploaded as CI artifacts on every push to master.
CI/CD Pipeline
The project uses GitHub Actions for continuous integration:
⚙️ Build & Test Workflow
Triggered on every push to master and on pull requests.
- Runs on
windows-latestwith .NET SDK 8.0 - Restores NuGet packages
- Builds in Release configuration
- Runs all 2,389 tests with code coverage
- Uploads test results (TRX) and coverage (Cobertura) as artifacts
- Outputs coverage summary in the workflow logs
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature - Write tests for new functionality
- Commit your changes:
git commit -m "Add your feature" - Push:
git push origin feature/your-feature - Open a Pull Request
Code Style
- Follow existing C# naming conventions (PascalCase for public members)
- Add XML doc comments to public interfaces and complex methods
- Include unit tests for all new logic
- Keep controllers thin — business logic belongs in repositories/services
Service Catalog
Vidly includes 33 business services organized into five domains. All services use constructor injection with repository interfaces and follow in-memory, list-based storage patterns.
🎬 Core Rental Operations
PricingService
Calculates daily rental rates with membership discounts, new-release premiums, and per-movie overrides. Provides GetMovieDailyRate() and GetBenefits() for tier-based pricing.
RentalReturnService
Orchestrates the return workflow: late-fee calculation with tier-based grace periods, condition assessment and damage charges, loyalty-point awards, and batch return processing.
RentalHistoryService
Filtered rental history queries, customer timelines, popular rental times, retention metrics, inventory forecasting, and loyalty score computation.
InventoryService
Real-time stock tracking, availability checks, low-stock alerts, and inventory audit reports.
ReservationService
Hold movies for customers with expiry management and conflict detection.
👥 Customer Management
MembershipTierService
Tier evaluation (Basic → Silver → Gold → Platinum) with upgrade/downgrade logic, benefit lookups, and renewal management.
LoyaltyPointsService
Point accrual, redemption, tier multipliers, transaction history, and balance queries.
CustomerSegmentationService
RFM analysis (Recency, Frequency, Monetary), customer clustering, and segment-based marketing insights.
CustomerActivityService
Activity feeds, engagement tracking, and customer lifecycle stage identification.
ChurnPredictorService
Churn risk scoring based on rental frequency decay, gap analysis, and re-engagement recommendations.
ParentalControlService
Age-based content filtering, parental profiles, rating restrictions, and viewing history controls.
🔍 Discovery & Content
RecommendationService
Content-based and collaborative filtering recommendations using genre preferences, rental history, and similar-user patterns.
MovieSimilarityService
Computes similarity scores between movies based on genre, rating, release date, and co-rental patterns.
MovieInsightsService
Deep analytics per movie: rental velocity, revenue trends, audience demographics, and performance comparisons.
MovieLifecycleService
Tracks movies through lifecycle stages (New Release → Popular → Catalog → Archive) with automated transitions.
CollectionService
Curated movie collections (staff picks, seasonal, thematic) with ordering and display management.
TaggingService
User-defined and system tags for movies, tag-based search, and tag cloud generation.
ReviewService
Customer reviews with ratings, helpfulness voting, moderation, and aggregate score computation.
WatchlistService
Personal watchlists with priority ordering, availability notifications, and sharing.
MovieNightPlannerService
Plan movie nights with group preferences, schedule coordination, and snack suggestions.
FranchiseTrackerService
Track movie franchises (series, sequels, prequels) with watch-order recommendations and completion tracking.
MovieComparisonService
Side-by-side movie comparison on ratings, revenue, rental count, and audience overlap.
💰 Commerce & Promotions
CouponService
Coupon creation, validation, redemption with percentage/fixed discounts, expiry, and usage limits.
GiftCardService
Gift card issuance, balance management, partial redemption, and transfer between customers.
BundleService
Movie bundles (rent 3 for price of 2), bundle creation, pricing rules, and availability checks.
SeasonalPromotionService
Time-bound promotions tied to seasons/holidays with automatic activation and genre-specific discounts.
DisputeResolutionService
Customer dispute filing, investigation workflows, resolution tracking, and refund processing.
📊 Analytics & Operations
RentalForecastService
Demand forecasting using historical patterns, seasonal adjustments, and trend analysis.
RevenueAnalyticsService
Revenue reporting by period, genre, tier, and trend. Includes linear regression forecasting with confidence intervals.
RatingEngineService
Aggregate rating computation with statistical analysis (mean, median, standard deviation, distribution).
DashboardService
Single-pass dashboard aggregation: top movies, top customers, genre revenue, membership breakdown, recent rentals, and monthly revenue — all in O(R).
StaffSchedulingService
Employee shift scheduling, availability management, conflict detection, and coverage optimization.
StaffPerformanceService
Staff performance metrics, KPI tracking, peer comparison, and review period analytics.
StoreEventService
In-store event planning (movie nights, premieres), RSVPs, capacity management, and calendar integration.
ReferralService
Customer referral program with tracking codes, reward attribution, and conversion analytics.
NotificationService
Customer notification management for due dates, availability, promotions, and account updates.
API Reference
Detailed method signatures and return types for key services. For complete API documentation, see SERVICES.md.
PricingService
| Method | Returns | Description |
|---|---|---|
GetMovieDailyRate(movie) | decimal | Base daily rate: new releases $5.99, catalog $2.99, per-movie overrides |
GetBenefits(tier) | MembershipBenefits | Tier benefits: discount %, extended days, max concurrent rentals |
RentalReturnService
| Method | Returns | Description |
|---|---|---|
ProcessReturn(rentalId, condition, returnDate) | ReturnReceipt | Full return workflow with late fees, damage charges, loyalty points |
ProcessBatchReturn(ids, condition, returnDate) | BatchReturnResult | Batch return with individual receipts and error tracking |
CalculateLateFee(dueDate, returnDate, dailyRate, tier) | ReturnLateFeeBreakdown | Late fee with grace period, tier discount, and cap |
GetOverdueRentals() | List<OverdueRentalInfo> | All overdue rentals with projected fees and recommended actions |
GetCustomerReturnProfile(customerId) | CustomerReturnProfile | Return history: on-time rate, late fees paid, reliability rating |
EstimateCurrentLateFee(rentalId) | LateFeeEstimate | Self-service “what would I owe?” projection |
DashboardService
| Method | Returns | Description |
|---|---|---|
GetDashboard() | DashboardData | Complete dashboard: stats, top movies/customers, genre revenue, membership breakdown, recent rentals, monthly revenue |
Internally uses AggregateSinglePass() to compute all metrics in a single O(R) pass over rentals, replacing 6 separate iterations.
ChurnPredictorService
| Method | Returns | Description |
|---|---|---|
PredictChurn(customerId) | ChurnPrediction | Churn risk score (0–1) with contributing factors |
GetAtRiskCustomers(threshold) | List<ChurnPrediction> | All customers above churn-risk threshold |
RecommendationService
| Method | Returns | Description |
|---|---|---|
GetRecommendations(customerId, count) | List<MovieRecommendation> | Personalized movie recommendations |
GetSimilarMovies(movieId, count) | List<MovieRecommendation> | Movies similar to a given title |