Error on Rendering a View to a String - asp.net-core

I am trying to render a view to a string in ASP Net Core 1 but keep receiving the error:
Operator '!' cannot be applied to operand of type ''
on this line:
view.RenderAsync(viewContext).GetAwaiter().GetResult();
I am confused as to why this might be the case and looking for some assistance.
Alot of the examples and help I have seen in this area relate to RC1. We are using the final core 1.0 here.
I'm using the following code which i found online:
public ViewRender(
IRazorViewEngine viewEngine,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
{
_viewEngine = viewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
public string Render<TModel>(string name, TModel model, ActionContext actionContext)
{
var viewEngineResult = _viewEngine.FindView(actionContext, name, true);
if (!viewEngineResult.Success)
{
throw new InvalidOperationException(string.Format("Couldn't find view '{0}'", name));
}
var view = viewEngineResult.View;
using (var output = new StringWriter())
{
var viewContext = new ViewContext(
actionContext,
view,
new ViewDataDictionary<TModel>(
metadataProvider: new EmptyModelMetadataProvider(),
modelState: new ModelStateDictionary())
{
Model = model
},
new TempDataDictionary(
actionContext.HttpContext,
_tempDataProvider),
output,
new HtmlHelperOptions());
view.RenderAsync(viewContext).GetAwaiter().GetResult();
return output.ToString();
}
}
}

Related

Why are my swagger docs showing 'additionalProperties = false' for my custom schema filter?

I have this SchemaFilter in my swagger config
public class SmartEnumSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (!TryGetSmartEnumValues(context.Type, out var values))
{
return;
}
var openApiInts = new OpenApiArray();
openApiInts.AddRange(values.Select(x => new OpenApiInteger(x.Value)));
schema.Type = "integer";
schema.Enum = openApiInts;
schema.Properties = null;
schema.Description = string.Join(", ", values.Select(v => $"{v.Value}: {v.Name}"));
}
}
It is working well, but for some reason this "additional properties" always appears in the docs:
But only for this particular schema - all the other schemas don't have it. Is there some way of removing it?
I tried setting both
schema.AdditionalProperties = null;
schema.AdditionalPropertiesAllowed = false;
but it made no difference

ASP.NET CORE using ADO.NET with AutoMapper

What is the proper way of using AutoMapper with ADO.NET in ASP.NET Core in generic way?
Also the SQL query has the same column names as in class of <T>
In specified example variable result is always empty list, so automapper could not map object properties to DbDataReader columns.
public class CustomDbContext : BaseRepository
{
readonly DbConnection dbConn;
public CustomDbContext(RepoDbContext context) : base(context)
{
dbConn = context.Database.GetDbConnection();
}
public async Task<List<T>> Get<T>(string sql) where T : class
{
var config = new AutoMapper.MapperConfiguration(cfg =>
{
cfg.CreateMap<DbDataReader, List<T>>();
});
var mapper = config.CreateMapper();
await dbConn.OpenAsync();
using (var command = dbConn.CreateCommand())
{
command.CommandText = sql;
var reader = await command.ExecuteReaderAsync();
var result = new List<T>();
if (reader.HasRows)
{
await reader.ReadAsync();
result = mapper.Map<DbDataReader, List<T>>(reader);
}
reader.Dispose();
return result;
}
}
}
Should I specify more detailed AutoMapper configuration or it can't be done this way?
Try using interfaces as IDataReader and IEnumerable instead of classes DbDataReader and List.
public async Task<List<T>> Get<T>(string sql) where T : class
{
var config = new AutoMapper.MapperConfiguration(cfg =>
{
cfg.CreateMap<IDataReader, IEnumerable<T>>();
});
var mapper = config.CreateMapper();
await dbConn.OpenAsync();
using (var command = dbConn.CreateCommand())
{
command.CommandText = sql;
var reader = await command.ExecuteReaderAsync();
var result = new List<T>();
if (reader.HasRows)
{
await reader.ReadAsync();
result = mapper.Map<IDataReader, IEnumerable<T>>(reader).ToList();
}
reader.Dispose();
return result;
}
}

How to test model binder in ASP.Net MVC 6?

I'm trying to write a unit test for a custom model binder in ASP.Net MVC 6. It seems simple enough. The model binder has a single BindModelAsync method which takes a ModelBindingContext parameter.
In my unit test, I'm trying to figure out how to fake the ModelBindingContext. At first, I thought I could use the default constructor and set the properties on the object that I need. This works for all of the properties except ModelType which is not settable.
I then looked at the static ModelBindingContext.CreateBindingContext but it takes a bunch of scary looking parameters. Looking at how some of the model binding tests within the MVC repo are written, it seems like it is not possible for me to mock the ModelBindingContext.ModelType (unless maybe I copy/paste those 6 classes from Microsoft.AspNetCore.Mvc.TestCommon).
Is there something simple/easy I am missing?
I've had some success in getting it working for some simple form and query string values. AspNetCore.Mvc v1.1.3
private static DefaultModelBindingContext GetBindingContext(IValueProvider valueProvider, Type modelType)
{
var metadataProvider = new EmptyModelMetadataProvider();
var bindingContext = new DefaultModelBindingContext
{
ModelMetadata = metadataProvider.GetMetadataForType(modelType),
ModelName = modelType.Name,
ModelState = new ModelStateDictionary(),
ValueProvider = valueProvider,
};
return bindingContext;
}
Using a query string provider
[TestMethod]
public async Task QueryStringValueProviderTest()
{
var binder = new MyModelBinder();
var queryCollection = new QueryCollection(
new Dictionary<string, StringValues>()
{
{ "param1", new StringValues("1") },
{ "param2", new StringValues("2") },
});
var vp = new QueryStringValueProvider(BindingSource.Query, queryCollection, CultureInfo.CurrentCulture);
var context = GetBindingContext(vp, typeof(MyModel));
await binder.BindModelAsync(context);
var resultModel = context.Result.Model as MyModel;
//TODO Asserts
}
Using a form collection provider
[TestMethod]
public async Task FormValueProviderTest()
{
var binder = new MyModelBinder();
var formCollection = new FormCollection(
new Dictionary<string, StringValues>()
{
{ "param1", new StringValues("1") },
{ "param2", new StringValues("2") }
});
var vp = new FormValueProvider(BindingSource.Form, formCollection, CultureInfo.CurrentCulture);
var context = GetBindingContext(vp, typeof(MyModel));
await binder.BindModelAsync(context);
var resultModel = context.Result.Model as MyModel;
//TODO asserts
}

Value cannot be null. Parameter name: view

I was trying to render a dynamic view into string.I got the idea from here and it is working well locally but on hosting I am getting the following error.My attempt is to convert the string to bytes for sending email
Value cannot be null. Parameter name: view
Controller
public ActionResult Index(int RegId)
{
try
{
var _mdlReceiptPdf = new ReceiptPdfVM
{
...
...
};
string result = RazorViewToString.RenderRazorViewToString(this, Server.MapPath("~/Views/Shared/_Receipts.cshtml"), _mdlReceiptPdf);
StringReader _sr = new StringReader(result);
return Json(result, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json(ex.Message, JsonRequestBehavior.AllowGet);
}
}
Util.cs
public static class RazorViewToString
{
public static string RenderRazorViewToString(this Controller controller, string viewName, object model)
{
controller.ViewData.Model = model;
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(controller.ControllerContext, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
}
I had this problem. In my case, it turned out that the partial view wasn't being uploaded to the hosted website because in the File Properties for the partial view, the BuildAction was set to None instead of Content
Yeah looks like this error is saying view can't be found.
In my case I had a typo for the view name in the controller.
_QuickView.cshtml instead of QuickView.cshtml

Object reference not set to an instance of an object when using SPGridViewPager

It's my first sharepoint project and eveything looks very confusing.
I need to have a SPGridView with paging.
Here is an entire code of mx webpart:
using System;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
namespace FirstSPGridView.VisualWebPart1
{
[ToolboxItemAttribute(false)]
public class VisualWebPart1 : WebPart
{
// Visual Studio might automatically update this path when you change the Visual Web Part project item.
private const string _ascxPath = #"~/_CONTROLTEMPLATES/FirstSPGridView/SPGridViewWebPartTest/VisualWebPart1UserControl.ascx";
SPGridView _grid;
protected override void CreateChildControls()
{
base.CreateChildControls();
try
{
SPSite mySite = SPContext.Current.Site;
SPWeb myWeb = mySite.OpenWeb();
//Using RunWithElevatedPrivileges
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite siteCollection = new SPSite(mySite.ID))
{
using (SPWeb web = siteCollection.OpenWeb(myWeb.ID))
{
_grid = new SPGridView();
_grid.AutoGenerateColumns = false;
_grid.PageSize = 3;
_grid.AllowPaging = true;
_grid.DataSource = SelectData();
Controls.Add(_grid);
SPGridViewPager pager = new SPGridViewPager();
pager.GridViewId = _grid.ID;
this.Controls.Add(pager);
}
}
});
}
catch (Exception ex)
{ }
}
protected sealed override void Render(HtmlTextWriter writer)
{
try
{
GenerateColumns();
_grid.DataBind();
base.Render(writer);
}
catch (Exception e)
{
throw new NotImplementedException();
}
}
private void GenerateColumns()
{
BoundField clientNameColumn = new BoundField();
clientNameColumn.HeaderText = "Client";
clientNameColumn.DataField = "LastName";
_grid.Columns.Add(clientNameColumn);
BoundField birthDayColumn = new BoundField();
birthDayColumn.HeaderText = "BirthDate";
birthDayColumn.DataField = "BirthDate";
_grid.Columns.Add(birthDayColumn);
}
public DataTable SelectData()
{
var dataGet = new DataTable();
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (
var conn =
new SqlConnection(
"Data Source=localhost;Initial Catalog=AdventureWorksDW2008R2;Integrated Security=True")
)
{
var adapter = new SqlDataAdapter();
adapter.SelectCommand =
new SqlCommand("Select TOP 100 LastName,Birthdate FROM DimCustomer");
adapter.SelectCommand.Connection = conn;
conn.Open();
adapter.Fill(dataGet);
}
});
return dataGet;
}
}
}
Everything was working (except paging until I added this code:
SPGridViewPager pager = new SPGridViewPager();
pager.GridViewId = _grid.ID;
this.Controls.Add(pager);
After that I get an exception on the Render method here:
base.Render(writer);
StackTrace is:
at System.Web.UI.Control.FindControl(String id, Int32 pathOffset)\r\n at Microsoft.SharePoint.WebControls.Menu.FindControlByWalking(Control namingContainer, String id)\r\n at Microsoft.SharePoint.WebControls.SPGridViewPager.get_GridViewControl()\r\n at Microsoft.SharePoint.WebControls.SPGridViewPager.Render(HtmlTextWriter output)\r\n at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)\r\n at System.Web.UI.WebControls.WebControl.RenderContents(HtmlTextWriter writer)\r\n at System.Web.UI.WebControls.WebControl.Render(HtmlTextWriter writer)\r\n at FirstSPGridView.VisualWebPart1.VisualWebPart1.Render(HtmlTextWriter writer)
How can I fix that error?
You must just set ID for _grid.
For example, _grid.ID = "_gridView";