1 // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. 2 3 using System.ComponentModel; 4 using System.Diagnostics; 5 using System.Diagnostics.CodeAnalysis; 6 using System.Globalization; 7 using System.IO; 8 using System.Web.WebPages.Instrumentation; 9 using System.Web.WebPages.Resources; 10 11 /* 12 WebPage class hierarchy 13 14 WebPageExecutingBase The base class for all Plan9 files (_pagestart, _appstart, and regular pages) 15 ApplicationStartPage Used for _appstart.cshtml 16 WebPageRenderingBase 17 StartPage Used for _pagestart.cshtml 18 WebPageBase 19 WebPage Plan9Pages 20 ViewWebPage? MVC Views 21 HelperPage Base class for Web Pages in App_Code. 22 */ 23 24 namespace System.Web.WebPages 25 { 26 // The base class for all CSHTML files (_pagestart, _appstart, and regular pages) 27 public abstract class WebPageExecutingBase 28 { 29 private IVirtualPathFactory _virtualPathFactory; 30 private DynamicHttpApplicationState _dynamicAppState; 31 private InstrumentationService _instrumentationService = null; 32 33 internal InstrumentationService InstrumentationService 34 { 35 get 36 { 37 if (_instrumentationService == null) 38 { 39 _instrumentationService = new InstrumentationService(); 40 } 41 return _instrumentationService; 42 } 43 set { _instrumentationService = value; } 44 } 45 46 public virtual HttpApplicationStateBase AppState 47 { 48 get 49 { 50 if (Context != null) 51 { 52 return Context.Application; 53 } 54 return null; 55 } 56 } 57 58 public virtual dynamic App 59 { 60 get 61 { 62 if (_dynamicAppState == null && AppState != null) 63 { 64 _dynamicAppState = new DynamicHttpApplicationState(AppState); 65 } 66 return _dynamicAppState; 67 } 68 } 69 70 public virtual HttpContextBase Context { get; set; } 71 72 public virtual string VirtualPath { get; set; } 73 74 [EditorBrowsable(EditorBrowsableState.Never)] 75 public virtual IVirtualPathFactory VirtualPathFactory 76 { 77 get { return _virtualPathFactory ?? VirtualPathFactoryManager.Instance; } 78 set { _virtualPathFactory = value; } 79 } 80 81 [EditorBrowsable(EditorBrowsableState.Never)] Execute()82 public abstract void Execute(); 83 Href(string path, params object[] pathParts)84 public virtual string Href(string path, params object[] pathParts) 85 { 86 return UrlUtil.Url(VirtualPath, path, pathParts); 87 } 88 BeginContext(int startPosition, int length, bool isLiteral)89 protected internal void BeginContext(int startPosition, int length, bool isLiteral) 90 { 91 BeginContext(GetOutputWriter(), VirtualPath, startPosition, length, isLiteral); 92 } 93 BeginContext(string virtualPath, int startPosition, int length, bool isLiteral)94 protected internal void BeginContext(string virtualPath, int startPosition, int length, bool isLiteral) 95 { 96 BeginContext(GetOutputWriter(), virtualPath, startPosition, length, isLiteral); 97 } 98 BeginContext(TextWriter writer, int startPosition, int length, bool isLiteral)99 protected internal void BeginContext(TextWriter writer, int startPosition, int length, bool isLiteral) 100 { 101 BeginContext(writer, VirtualPath, startPosition, length, isLiteral); 102 } 103 BeginContext(TextWriter writer, string virtualPath, int startPosition, int length, bool isLiteral)104 protected internal void BeginContext(TextWriter writer, string virtualPath, int startPosition, int length, bool isLiteral) 105 { 106 // Double check that the instrumentation service is active because WriteAttribute always calls this 107 if (InstrumentationService.IsAvailable) 108 { 109 InstrumentationService.BeginContext(Context, 110 virtualPath, 111 writer, 112 startPosition, 113 length, 114 isLiteral); 115 } 116 } 117 EndContext(int startPosition, int length, bool isLiteral)118 protected internal void EndContext(int startPosition, int length, bool isLiteral) 119 { 120 EndContext(GetOutputWriter(), VirtualPath, startPosition, length, isLiteral); 121 } 122 EndContext(string virtualPath, int startPosition, int length, bool isLiteral)123 protected internal void EndContext(string virtualPath, int startPosition, int length, bool isLiteral) 124 { 125 EndContext(GetOutputWriter(), virtualPath, startPosition, length, isLiteral); 126 } 127 EndContext(TextWriter writer, int startPosition, int length, bool isLiteral)128 protected internal void EndContext(TextWriter writer, int startPosition, int length, bool isLiteral) 129 { 130 EndContext(writer, VirtualPath, startPosition, length, isLiteral); 131 } 132 EndContext(TextWriter writer, string virtualPath, int startPosition, int length, bool isLiteral)133 protected internal void EndContext(TextWriter writer, string virtualPath, int startPosition, int length, bool isLiteral) 134 { 135 // Double check that the instrumentation service is active because WriteAttribute always calls this 136 if (InstrumentationService.IsAvailable) 137 { 138 InstrumentationService.EndContext(Context, 139 virtualPath, 140 writer, 141 startPosition, 142 length, 143 isLiteral); 144 } 145 } 146 GetDirectory(string virtualPath)147 internal virtual string GetDirectory(string virtualPath) 148 { 149 return VirtualPathUtility.GetDirectory(virtualPath); 150 } 151 152 /// <summary> 153 /// Normalizes path relative to the current virtual path and throws if a file does not exist at the location. 154 /// </summary> NormalizeLayoutPagePath(string layoutPagePath)155 internal string NormalizeLayoutPagePath(string layoutPagePath) 156 { 157 var virtualPath = NormalizePath(layoutPagePath); 158 // Look for it as specified, either absolute, relative or same folder 159 if (VirtualPathFactory.Exists(virtualPath)) 160 { 161 return virtualPath; 162 } 163 throw new HttpException(String.Format(CultureInfo.CurrentCulture, WebPageResources.WebPage_LayoutPageNotFound, layoutPagePath, virtualPath)); 164 } 165 NormalizePath(string path)166 public virtual string NormalizePath(string path) 167 { 168 // If it's relative, resolve it 169 return VirtualPathUtility.Combine(VirtualPath, path); 170 } 171 Write(HelperResult result)172 public abstract void Write(HelperResult result); 173 Write(object value)174 public abstract void Write(object value); 175 WriteLiteral(object value)176 public abstract void WriteLiteral(object value); 177 WriteAttribute(string name, PositionTagged<string> prefix, PositionTagged<string> suffix, params AttributeValue[] values)178 public virtual void WriteAttribute(string name, PositionTagged<string> prefix, PositionTagged<string> suffix, params AttributeValue[] values) 179 { 180 WriteAttributeTo(GetOutputWriter(), name, prefix, suffix, values); 181 } 182 WriteAttributeTo(TextWriter writer, string name, PositionTagged<string> prefix, PositionTagged<string> suffix, params AttributeValue[] values)183 public virtual void WriteAttributeTo(TextWriter writer, string name, PositionTagged<string> prefix, PositionTagged<string> suffix, params AttributeValue[] values) 184 { 185 WriteAttributeTo(VirtualPath, writer, name, prefix, suffix, values); 186 } 187 WriteAttributeTo(string pageVirtualPath, TextWriter writer, string name, PositionTagged<string> prefix, PositionTagged<string> suffix, params AttributeValue[] values)188 protected internal virtual void WriteAttributeTo(string pageVirtualPath, TextWriter writer, string name, PositionTagged<string> prefix, PositionTagged<string> suffix, params AttributeValue[] values) 189 { 190 bool first = true; 191 bool wroteSomething = false; 192 if (values.Length == 0) 193 { 194 // Explicitly empty attribute, so write the prefix and suffix 195 WritePositionTaggedLiteral(writer, pageVirtualPath, prefix); 196 WritePositionTaggedLiteral(writer, pageVirtualPath, suffix); 197 } 198 else 199 { 200 foreach (AttributeValue attrVal in values) 201 { 202 PositionTagged<object> val = attrVal.Value; 203 bool? boolVal = null; 204 if (val.Value is bool) 205 { 206 boolVal = (bool)val.Value; 207 } 208 209 if (val.Value != null && (boolVal == null || boolVal.Value)) 210 { 211 string valStr = val.Value as string; 212 if (valStr == null) 213 { 214 valStr = val.Value.ToString(); 215 } 216 if (boolVal != null) 217 { 218 Debug.Assert(boolVal.Value); 219 valStr = name; 220 } 221 222 if (first) 223 { 224 WritePositionTaggedLiteral(writer, pageVirtualPath, prefix); 225 first = false; 226 } 227 else 228 { 229 WritePositionTaggedLiteral(writer, pageVirtualPath, attrVal.Prefix); 230 } 231 BeginContext(writer, pageVirtualPath, attrVal.Value.Position, valStr.Length, isLiteral: attrVal.Literal); 232 if (attrVal.Literal) 233 { 234 WriteLiteralTo(writer, valStr); 235 } 236 else 237 { 238 WriteTo(writer, valStr); // Write value 239 } 240 EndContext(writer, pageVirtualPath, attrVal.Value.Position, valStr.Length, isLiteral: attrVal.Literal); 241 wroteSomething = true; 242 } 243 } 244 if (wroteSomething) 245 { 246 WritePositionTaggedLiteral(writer, pageVirtualPath, suffix); 247 } 248 } 249 } 250 WritePositionTaggedLiteral(TextWriter writer, string pageVirtualPath, string value, int position)251 private void WritePositionTaggedLiteral(TextWriter writer, string pageVirtualPath, string value, int position) 252 { 253 BeginContext(writer, pageVirtualPath, position, value.Length, isLiteral: true); 254 WriteLiteralTo(writer, value); 255 EndContext(writer, pageVirtualPath, position, value.Length, isLiteral: true); 256 } 257 WritePositionTaggedLiteral(TextWriter writer, string pageVirtualPath, PositionTagged<string> value)258 private void WritePositionTaggedLiteral(TextWriter writer, string pageVirtualPath, PositionTagged<string> value) 259 { 260 WritePositionTaggedLiteral(writer, pageVirtualPath, value.Value, value.Position); 261 } 262 263 // This method is called by generated code and needs to stay in sync with the parser WriteTo(TextWriter writer, HelperResult content)264 public static void WriteTo(TextWriter writer, HelperResult content) 265 { 266 if (content != null) 267 { 268 content.WriteTo(writer); 269 } 270 } 271 272 // This method is called by generated code and needs to stay in sync with the parser WriteTo(TextWriter writer, object content)273 public static void WriteTo(TextWriter writer, object content) 274 { 275 writer.Write(HttpUtility.HtmlEncode(content)); 276 } 277 278 // This method is called by generated code and needs to stay in sync with the parser WriteLiteralTo(TextWriter writer, object content)279 public static void WriteLiteralTo(TextWriter writer, object content) 280 { 281 writer.Write(content); 282 } 283 284 [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "A method is more appropriate in this case since a property likely already exists to hold this value")] GetOutputWriter()285 protected internal virtual TextWriter GetOutputWriter() 286 { 287 return TextWriter.Null; 288 } 289 } 290 } 291