{"action":"created","comment":{"url":"https://api.github.com/repos/aspnet/Mvc/pulls/comments/25144958","id":25144958,"diff_hunk":"@@ -0,0 +1,378 @@\n+﻿// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.\n+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n+\n+using System;\n+using System.Collections.Generic;\n+using System.Diagnostics;\n+using System.Linq;\n+\n+namespace Microsoft.AspNet.Mvc.ModelBinding\n+{\n+    /// <summary>\n+    /// Associates a model object with it's corresponding <see cref=\"ModelMetadata\"/>.\n+    /// </summary>\n+    [DebuggerDisplay(\"DeclaredType={Metadata.ModelType.Name} PropertyName={Metadata.PropertyName}\")]\n+    public class ModelExplorer\n+    {\n+        private readonly IModelMetadataProvider _metadataProvider;\n+\n+        private object _model;\n+        private Func<object, object> _modelAccessor;\n+        private Type _modelType;\n+        private List<ModelExplorer> _properties;\n+\n+        /// <summary>\n+        /// Creates a new <see cref=\"ModelExplorer\"/>.\n+        /// </summary>\n+        /// <param name=\"metadataProvider\">The <see cref=\"IModelMetadataProvider\"/>.</param>\n+        /// <param name=\"metadata\">The <see cref=\"ModelMetadata\"/>.</param>\n+        /// <param name=\"model\">The model object. May be <c>null</c>.</param>\n+        public ModelExplorer(\n+            [NotNull] IModelMetadataProvider metadataProvider, \n+            [NotNull] ModelMetadata metadata, \n+            object model)\n+        {\n+            _metadataProvider = metadataProvider;\n+            Metadata = metadata;\n+            _model = model;\n+        }\n+\n+        /// <summary>\n+        /// Creates a new <see cref=\"ModelExplorer\"/>.\n+        /// </summary>\n+        /// <param name=\"metadataProvider\">The <see cref=\"IModelMetadataProvider\"/>.</param>\n+        /// <param name=\"container\">The container <see cref=\"ModelExplorer\"/>.</param>\n+        /// <param name=\"metadata\">The <see cref=\"ModelMetadata\"/>.</param>\n+        /// <param name=\"modelAccessor\">A model accessor function. May be <c>null</c>.</param>\n+        public ModelExplorer(\n+            [NotNull] IModelMetadataProvider metadataProvider,\n+            [NotNull] ModelExplorer container,\n+            [NotNull] ModelMetadata metadata,\n+            Func<object, object> modelAccessor)\n+        {\n+            _metadataProvider = metadataProvider;\n+            Container = container;\n+            Metadata = metadata;\n+            _modelAccessor = modelAccessor;\n+        }\n+\n+        /// <summary>\n+        /// Creates a new <see cref=\"ModelExplorer\"/>.\n+        /// </summary>\n+        /// <param name=\"metadataProvider\">The <see cref=\"IModelMetadataProvider\"/>.</param>\n+        /// <param name=\"container\">The container <see cref=\"ModelExplorer\"/>.</param>\n+        /// <param name=\"metadata\">The <see cref=\"ModelMetadata\"/>.</param>\n+        /// <param name=\"model\">The model object. May be <c>null</c>.</param>\n+        public ModelExplorer(\n+            [NotNull] IModelMetadataProvider metadataProvider,\n+            [NotNull] ModelExplorer container,\n+            [NotNull] ModelMetadata metadata,\n+            object model)\n+        {\n+            _metadataProvider = metadataProvider;\n+            Container = container;\n+            Metadata = metadata;\n+            _model = model;\n+        }\n+\n+        /// <summary>\n+        /// Gets the container <see cref=\"ModelExplorer\"/>.\n+        /// </summary>\n+        /// <remarks>\n+        /// <para>\n+        /// The <see cref=\"Container\"/> will most commonly be set as a result of calling\n+        /// <see cref=\"GetExplorerForProperty(string)\"/>. In this case, the returned <see cref=\"ModelExplorer\"/> will\n+        /// have it's <see cref=\"Container\"/> set to the instance upon which <see cref=\"GetExplorerForProperty(string)\"/>\n+        /// was called.\n+        /// </para>\n+        /// <para>\n+        /// This however is not a requirement. The <see cref=\"Container\"/> is informational, and may not\n+        /// represent a type that defines the property represented by <see cref=\"Metadata\"/>. This can\n+        /// occur when constructing a <see cref=\"ModelExplorer\"/> based on evaluation of a complex\n+        /// expression.\n+        /// </para>\n+        /// <para>\n+        /// If calling code relies on a parent-child relationship between <see cref=\"ModelExplorer\"/>\n+        /// instances, then use <see cref=\"ModelMetadata.ContainerType\"/> to validate this assumption.\n+        /// </para>\n+        /// </remarks>\n+        public ModelExplorer Container { get; }\n+\n+        /// <summary>\n+        /// Gets the <see cref=\"ModelMetadata\"/>.\n+        /// </summary>\n+        public ModelMetadata Metadata { get; }\n+\n+        /// <summary>\n+        /// Gets the model object.\n+        /// </summary>\n+        /// <remarks>\n+        /// Retrieving the <see cref=\"Model\"/> object will execute model accessor function if this\n+        /// <see cref=\"ModelExplorer\"/> was provided with one.\n+        /// </remarks>\n+        public object Model\n+        {\n+            get\n+            {\n+                if (_model == null && _modelAccessor != null)\n+                {\n+                    Debug.Assert(Container != null);\n+                    _model = _modelAccessor(Container.Model);\n+\n+                    // Null-out the accessor so we don't invoke it repeatedly if it returns null.\n+                    _modelAccessor = null;\n+                }\n+\n+                return _model;\n+            }\n+        }\n+\n+        /// <remarks>\n+        /// Retrieving the <see cref=\"Model\"/> type will for execution of the model accessor function if this","path":"src/Microsoft.AspNet.Mvc.ModelBinding/Metadata/ModelExplorer.cs","position":131,"original_position":131,"commit_id":"15993efecdd470f65fe339f57266383c379d0f30","original_commit_id":"15993efecdd470f65fe339f57266383c379d0f30","user":{"login":"dougbu","id":6431421,"avatar_url":"https://avatars.githubusercontent.com/u/6431421?v=3","gravatar_id":"","url":"https://api.github.com/users/dougbu","html_url":"https://github.com/dougbu","followers_url":"https://api.github.com/users/dougbu/followers","following_url":"https://api.github.com/users/dougbu/following{/other_user}","gists_url":"https://api.github.com/users/dougbu/gists{/gist_id}","starred_url":"https://api.github.com/users/dougbu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dougbu/subscriptions","organizations_url":"https://api.github.com/users/dougbu/orgs","repos_url":"https://api.github.com/users/dougbu/repos","events_url":"https://api.github.com/users/dougbu/events{/privacy}","received_events_url":"https://api.github.com/users/dougbu/received_events","type":"User","site_admin":false},"body":"nit: `Retrieving the <see cref=\"ModelType\"/> will execute model accessor ...`","created_at":"2015-02-23T05:54:05Z","updated_at":"2015-02-23T05:54:05Z","html_url":"https://github.com/aspnet/Mvc/pull/2043#discussion_r25144958","pull_request_url":"https://api.github.com/repos/aspnet/Mvc/pulls/2043","_links":{"self":{"href":"https://api.github.com/repos/aspnet/Mvc/pulls/comments/25144958"},"html":{"href":"https://github.com/aspnet/Mvc/pull/2043#discussion_r25144958"},"pull_request":{"href":"https://api.github.com/repos/aspnet/Mvc/pulls/2043"}}},"pull_request":{"url":"https://api.github.com/repos/aspnet/Mvc/pulls/2043","id":29642691,"html_url":"https://github.com/aspnet/Mvc/pull/2043","diff_url":"https://github.com/aspnet/Mvc/pull/2043.diff","patch_url":"https://github.com/aspnet/Mvc/pull/2043.patch","issue_url":"https://api.github.com/repos/aspnet/Mvc/issues/2043","number":2043,"state":"open","locked":false,"title":"[Design] Removing ModelMetadata.Model","user":{"login":"rynowak","id":1430011,"avatar_url":"https://avatars.githubusercontent.com/u/1430011?v=3","gravatar_id":"","url":"https://api.github.com/users/rynowak","html_url":"https://github.com/rynowak","followers_url":"https://api.github.com/users/rynowak/followers","following_url":"https://api.github.com/users/rynowak/following{/other_user}","gists_url":"https://api.github.com/users/rynowak/gists{/gist_id}","starred_url":"https://api.github.com/users/rynowak/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rynowak/subscriptions","organizations_url":"https://api.github.com/users/rynowak/orgs","repos_url":"https://api.github.com/users/rynowak/repos","events_url":"https://api.github.com/users/rynowak/events{/privacy}","received_events_url":"https://api.github.com/users/rynowak/received_events","type":"User","site_admin":false},"body":"Removing `ModelMetadata.Model` and replacing with a new abstraction `ModelExplorer`. \r\n\r\nThis means that any functionality related to the actual Model value has to leave `ModelMetadata`. `ModelMetdata` is now dedicated to static functionality around the *declared type* of a model.\r\n\r\n`ModelExplorer` is a new abstraction for consumers that want to walk a runtime model and consume model metadata at the same time. `ModelExplorer` is based on the *runtime type* of the model. Of course, the model may be `null`, so we have the standard fallback-to-declared-type functionality.\r\n\r\n\r\nSummary of the impact of this change:\r\n\r\nAnything that handles display needs to work on `ModelExplorer` now. This includes all the `HtmlHelper` protected methods, expression processing, display templates and VDD.\r\n\r\nValidation makes use of `ModelExplorer` as it's often concerned with property traversal.\r\n\r\nModel Binding does not make use of `ModelExplorer` as it needs to set data. The model binding context now has a `Model` property to pass the container when binding subproperties. Note that some model binding code invokes validators, and so needs to use `ModelExplorer` for this purpose.\r\n\r\n","created_at":"2015-02-19T19:49:07Z","updated_at":"2015-02-23T05:54:05Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4bac44661269500cb195f6b93f1a8eea401b8aa1","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/aspnet/Mvc/pulls/2043/commits","review_comments_url":"https://api.github.com/repos/aspnet/Mvc/pulls/2043/comments","review_comment_url":"https://api.github.com/repos/aspnet/Mvc/pulls/comments{/number}","comments_url":"https://api.github.com/repos/aspnet/Mvc/issues/2043/comments","statuses_url":"https://api.github.com/repos/aspnet/Mvc/statuses/15993efecdd470f65fe339f57266383c379d0f30","head":{"label":"aspnet:mm-model-removal","ref":"mm-model-removal","sha":"15993efecdd470f65fe339f57266383c379d0f30","user":{"login":"aspnet","id":6476660,"avatar_url":"https://avatars.githubusercontent.com/u/6476660?v=3","gravatar_id":"","url":"https://api.github.com/users/aspnet","html_url":"https://github.com/aspnet","followers_url":"https://api.github.com/users/aspnet/followers","following_url":"https://api.github.com/users/aspnet/following{/other_user}","gists_url":"https://api.github.com/users/aspnet/gists{/gist_id}","starred_url":"https://api.github.com/users/aspnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aspnet/subscriptions","organizations_url":"https://api.github.com/users/aspnet/orgs","repos_url":"https://api.github.com/users/aspnet/repos","events_url":"https://api.github.com/users/aspnet/events{/privacy}","received_events_url":"https://api.github.com/users/aspnet/received_events","type":"Organization","site_admin":false},"repo":{"id":15126429,"name":"Mvc","full_name":"aspnet/Mvc","owner":{"login":"aspnet","id":6476660,"avatar_url":"https://avatars.githubusercontent.com/u/6476660?v=3","gravatar_id":"","url":"https://api.github.com/users/aspnet","html_url":"https://github.com/aspnet","followers_url":"https://api.github.com/users/aspnet/followers","following_url":"https://api.github.com/users/aspnet/following{/other_user}","gists_url":"https://api.github.com/users/aspnet/gists{/gist_id}","starred_url":"https://api.github.com/users/aspnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aspnet/subscriptions","organizations_url":"https://api.github.com/users/aspnet/orgs","repos_url":"https://api.github.com/users/aspnet/repos","events_url":"https://api.github.com/users/aspnet/events{/privacy}","received_events_url":"https://api.github.com/users/aspnet/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/aspnet/Mvc","description":"Model view controller framework for building dynamic web sites with clean separation of concerns, including the merged MVC, Web API, and Web Pages w/ Razor.","fork":false,"url":"https://api.github.com/repos/aspnet/Mvc","forks_url":"https://api.github.com/repos/aspnet/Mvc/forks","keys_url":"https://api.github.com/repos/aspnet/Mvc/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aspnet/Mvc/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aspnet/Mvc/teams","hooks_url":"https://api.github.com/repos/aspnet/Mvc/hooks","issue_events_url":"https://api.github.com/repos/aspnet/Mvc/issues/events{/number}","events_url":"https://api.github.com/repos/aspnet/Mvc/events","assignees_url":"https://api.github.com/repos/aspnet/Mvc/assignees{/user}","branches_url":"https://api.github.com/repos/aspnet/Mvc/branches{/branch}","tags_url":"https://api.github.com/repos/aspnet/Mvc/tags","blobs_url":"https://api.github.com/repos/aspnet/Mvc/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aspnet/Mvc/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aspnet/Mvc/git/refs{/sha}","trees_url":"https://api.github.com/repos/aspnet/Mvc/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aspnet/Mvc/statuses/{sha}","languages_url":"https://api.github.com/repos/aspnet/Mvc/languages","stargazers_url":"https://api.github.com/repos/aspnet/Mvc/stargazers","contributors_url":"https://api.github.com/repos/aspnet/Mvc/contributors","subscribers_url":"https://api.github.com/repos/aspnet/Mvc/subscribers","subscription_url":"https://api.github.com/repos/aspnet/Mvc/subscription","commits_url":"https://api.github.com/repos/aspnet/Mvc/commits{/sha}","git_commits_url":"https://api.github.com/repos/aspnet/Mvc/git/commits{/sha}","comments_url":"https://api.github.com/repos/aspnet/Mvc/comments{/number}","issue_comment_url":"https://api.github.com/repos/aspnet/Mvc/issues/comments{/number}","contents_url":"https://api.github.com/repos/aspnet/Mvc/contents/{+path}","compare_url":"https://api.github.com/repos/aspnet/Mvc/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aspnet/Mvc/merges","archive_url":"https://api.github.com/repos/aspnet/Mvc/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aspnet/Mvc/downloads","issues_url":"https://api.github.com/repos/aspnet/Mvc/issues{/number}","pulls_url":"https://api.github.com/repos/aspnet/Mvc/pulls{/number}","milestones_url":"https://api.github.com/repos/aspnet/Mvc/milestones{/number}","notifications_url":"https://api.github.com/repos/aspnet/Mvc/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aspnet/Mvc/labels{/name}","releases_url":"https://api.github.com/repos/aspnet/Mvc/releases{/id}","created_at":"2013-12-12T03:54:00Z","updated_at":"2015-02-23T04:32:26Z","pushed_at":"2015-02-23T04:32:30Z","git_url":"git://github.com/aspnet/Mvc.git","ssh_url":"git@github.com:aspnet/Mvc.git","clone_url":"https://github.com/aspnet/Mvc.git","svn_url":"https://github.com/aspnet/Mvc","homepage":"","size":80531,"stargazers_count":1401,"watchers_count":1401,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":416,"mirror_url":null,"open_issues_count":229,"forks":416,"open_issues":229,"watchers":1401,"default_branch":"dev"}},"base":{"label":"aspnet:dev","ref":"dev","sha":"4f0ba26c7934d01cb195e2b26f7f913fbe2742be","user":{"login":"aspnet","id":6476660,"avatar_url":"https://avatars.githubusercontent.com/u/6476660?v=3","gravatar_id":"","url":"https://api.github.com/users/aspnet","html_url":"https://github.com/aspnet","followers_url":"https://api.github.com/users/aspnet/followers","following_url":"https://api.github.com/users/aspnet/following{/other_user}","gists_url":"https://api.github.com/users/aspnet/gists{/gist_id}","starred_url":"https://api.github.com/users/aspnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aspnet/subscriptions","organizations_url":"https://api.github.com/users/aspnet/orgs","repos_url":"https://api.github.com/users/aspnet/repos","events_url":"https://api.github.com/users/aspnet/events{/privacy}","received_events_url":"https://api.github.com/users/aspnet/received_events","type":"Organization","site_admin":false},"repo":{"id":15126429,"name":"Mvc","full_name":"aspnet/Mvc","owner":{"login":"aspnet","id":6476660,"avatar_url":"https://avatars.githubusercontent.com/u/6476660?v=3","gravatar_id":"","url":"https://api.github.com/users/aspnet","html_url":"https://github.com/aspnet","followers_url":"https://api.github.com/users/aspnet/followers","following_url":"https://api.github.com/users/aspnet/following{/other_user}","gists_url":"https://api.github.com/users/aspnet/gists{/gist_id}","starred_url":"https://api.github.com/users/aspnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aspnet/subscriptions","organizations_url":"https://api.github.com/users/aspnet/orgs","repos_url":"https://api.github.com/users/aspnet/repos","events_url":"https://api.github.com/users/aspnet/events{/privacy}","received_events_url":"https://api.github.com/users/aspnet/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/aspnet/Mvc","description":"Model view controller framework for building dynamic web sites with clean separation of concerns, including the merged MVC, Web API, and Web Pages w/ Razor.","fork":false,"url":"https://api.github.com/repos/aspnet/Mvc","forks_url":"https://api.github.com/repos/aspnet/Mvc/forks","keys_url":"https://api.github.com/repos/aspnet/Mvc/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aspnet/Mvc/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aspnet/Mvc/teams","hooks_url":"https://api.github.com/repos/aspnet/Mvc/hooks","issue_events_url":"https://api.github.com/repos/aspnet/Mvc/issues/events{/number}","events_url":"https://api.github.com/repos/aspnet/Mvc/events","assignees_url":"https://api.github.com/repos/aspnet/Mvc/assignees{/user}","branches_url":"https://api.github.com/repos/aspnet/Mvc/branches{/branch}","tags_url":"https://api.github.com/repos/aspnet/Mvc/tags","blobs_url":"https://api.github.com/repos/aspnet/Mvc/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aspnet/Mvc/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aspnet/Mvc/git/refs{/sha}","trees_url":"https://api.github.com/repos/aspnet/Mvc/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aspnet/Mvc/statuses/{sha}","languages_url":"https://api.github.com/repos/aspnet/Mvc/languages","stargazers_url":"https://api.github.com/repos/aspnet/Mvc/stargazers","contributors_url":"https://api.github.com/repos/aspnet/Mvc/contributors","subscribers_url":"https://api.github.com/repos/aspnet/Mvc/subscribers","subscription_url":"https://api.github.com/repos/aspnet/Mvc/subscription","commits_url":"https://api.github.com/repos/aspnet/Mvc/commits{/sha}","git_commits_url":"https://api.github.com/repos/aspnet/Mvc/git/commits{/sha}","comments_url":"https://api.github.com/repos/aspnet/Mvc/comments{/number}","issue_comment_url":"https://api.github.com/repos/aspnet/Mvc/issues/comments{/number}","contents_url":"https://api.github.com/repos/aspnet/Mvc/contents/{+path}","compare_url":"https://api.github.com/repos/aspnet/Mvc/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aspnet/Mvc/merges","archive_url":"https://api.github.com/repos/aspnet/Mvc/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aspnet/Mvc/downloads","issues_url":"https://api.github.com/repos/aspnet/Mvc/issues{/number}","pulls_url":"https://api.github.com/repos/aspnet/Mvc/pulls{/number}","milestones_url":"https://api.github.com/repos/aspnet/Mvc/milestones{/number}","notifications_url":"https://api.github.com/repos/aspnet/Mvc/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aspnet/Mvc/labels{/name}","releases_url":"https://api.github.com/repos/aspnet/Mvc/releases{/id}","created_at":"2013-12-12T03:54:00Z","updated_at":"2015-02-23T04:32:26Z","pushed_at":"2015-02-23T04:32:30Z","git_url":"git://github.com/aspnet/Mvc.git","ssh_url":"git@github.com:aspnet/Mvc.git","clone_url":"https://github.com/aspnet/Mvc.git","svn_url":"https://github.com/aspnet/Mvc","homepage":"","size":80531,"stargazers_count":1401,"watchers_count":1401,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":416,"mirror_url":null,"open_issues_count":229,"forks":416,"open_issues":229,"watchers":1401,"default_branch":"dev"}},"_links":{"self":{"href":"https://api.github.com/repos/aspnet/Mvc/pulls/2043"},"html":{"href":"https://github.com/aspnet/Mvc/pull/2043"},"issue":{"href":"https://api.github.com/repos/aspnet/Mvc/issues/2043"},"comments":{"href":"https://api.github.com/repos/aspnet/Mvc/issues/2043/comments"},"review_comments":{"href":"https://api.github.com/repos/aspnet/Mvc/pulls/2043/comments"},"review_comment":{"href":"https://api.github.com/repos/aspnet/Mvc/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/aspnet/Mvc/pulls/2043/commits"},"statuses":{"href":"https://api.github.com/repos/aspnet/Mvc/statuses/15993efecdd470f65fe339f57266383c379d0f30"}}}}