I just updated our RazorEngine reference to version 3.7.5. A bunch of things seems to have changed and became obsolete.
For most things I figured out 'the new way', except for 1 thing: getting an ITemplate instance.
We used to use a TemplateService instance. That had a method Resolve, which returns an ITemplate instance.
The TemplateService was replaced with IRazorEngineService. This doesn't have any method returning an ITemplate.
What's the correct way to retrieve one?
As I already discussed this on some threads here some quotes:
Can you elaborate the reasons why you need access to instances of that interface directly?
I decided to remove direct access to it as it isn't easy to use and mostly doesn't do what you think it does. It also can cause problems in case you use the Isolation API.
https://github.com/Antaris/RazorEngine/issues/225
If its about setting custom layouts the proper upgrade path is to use a custom TemplateBase and make use of the ViewBag (as discussed on the linked issue).
The other more interesting use case is to get data OUT of the template.
This is discussed in detail here: https://github.com/Antaris/RazorEngine/issues/238
Here is a code sample on how to get out the 'Subject' from the given template
Template:
#model HelloWorldModel
#{
Layout = "CI";
Subject = "Hello World";
}
Hello #Model.Name,<br/>
this is a test email...
Code (simplified)
class CustomDataHolder {
public string Destination { get; set; }
public string Subject { get; set; }
}
// In the custom TemplateBase class:
public string Subject { get { return Viewbag.DataHolder.Subject; }; set { Viewbag.DataHolder.Subject = value; } }
// Your code
public static Task SendEmailAsync<T>(string templateName, string destination, T model)
{
var holder = new CustomDataHolder ();
dynamic viewbag = new DynamicViewBag();
viewbag.DataHolder = holder;
holder.Destination= destination;
var body = Engine.Razor.Run(templateName, typeof(T), model, (DynamicViewBag)viewbag);
MailMessage msg = new MailMessage();
msg.To.Add(new MailAddress(holder.Destination));
msg.Subject = holder.Subject;
msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(body, null, MediaTypeNames.Text.Html));
SmtpClient smtpClient = new SmtpClient();
return smtpClient.SendMailAsync(msg);
}
Hope this covers your use case. Otherwise please add more information to your question on what you trying to achieve with the ITemplate instances....
Related
I have a ASP.NET WebApi project that I am working on. The boss would like the returns to support "partial response", meaning that though the data model might contain 50 fields, the client should be able to request specific fields for the response. The reason being that if they are implementing for example a list they simply don't need the overhead of all 50 fields, they might just want the First Name, Last Name and Id to generate the list. Thus far I have implemented a solution by using a custom Contract Resolver (DynamicContractResolver) such that when a request comes in I am peeking into it through a filter (FieldListFilter) in the OnActionExecuting method and determining if a field named "FieldList" is present and then if it is I am replacing the current ContractResolver with a new instance of my DynamicContractResolver and I pass the fieldlist to the constructor.
Some sample code
DynamicContractResolver.cs
protected override IList<JsonProperty> CreateProperties(Type type, Newtonsoft.Json.MemberSerialization memberSerialization)
{
List<String> fieldList = ConvertFieldStringToList();
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
if (fieldList.Count == 0)
{
return properties;
}
// If we have fields, check that FieldList is one of them.
if (!fieldList.Contains("FieldList"))
// If not then add it, FieldList must ALWAYS be a part of any non null field list.
fieldList.Add("FieldList");
if (!fieldList.Contains("Data"))
fieldList.Add("Data");
if (!fieldList.Contains("FilterText"))
fieldList.Add("FilterText");
if (!fieldList.Contains("PageNumber"))
fieldList.Add("PageNumber");
if (!fieldList.Contains("RecordsReturned"))
fieldList.Add("RecordsReturned");
if (!fieldList.Contains("RecordsFound"))
fieldList.Add("RecordsFound");
for (int ctr = properties.Count-1; ctr >= 0; ctr--)
{
foreach (string field in fieldList)
{
if (field.Trim() == properties[ctr].PropertyName)
{
goto Found;
}
}
System.Diagnostics.Debug.WriteLine("Remove Property at Index " + ctr + " Named: " + properties[ctr].PropertyName);
properties.RemoveAt(ctr);
// Exit point for the inner foreach. Nothing to do here.
Found: { }
}
return properties;
}
FieldListFilter.cs
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
// We need to determine if there is a FieldList property of the model that is being used.
// First get a reference to the model.
var modelObject = actionContext.ActionArguments.FirstOrDefault().Value;
string fieldList = string.Empty;
try
{
// Using reflection, attempt to get the value of the FieldList property
var fieldListTemp = modelObject.GetType().GetProperty("FieldList").GetValue(modelObject);
// If it is null then use an empty string
if (fieldListTemp != null)
{
fieldList = fieldListTemp.ToString();
}
}
catch (Exception)
{
fieldList = string.Empty;
}
// Update the global ContractResolver with the fieldList value but for efficiency only do it if they are not the same as the current ContractResolver.
if (((DynamicContractResolver)GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver).FieldList != fieldList)
{
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new DynamicContractResolver(fieldList);
}
}
I can then send a request with the json content payload looking as such:
{
"FieldList":"NameFirst,NameLast,Id",
"Data":[
{
"Id":1234
},
{
"Id":1235
}
]
}
and I will receive a response like so:
{
"FieldList":"NameFirst,NameLast,Id",
"Data":[
{
"NameFirst":"Brian",
"NameLast":"Mueller",
"Id":1234
},
{
"NameFirst":"Brian",
"NameLast":"Mueller",
"Id":1235
}
]
}
I believe that using the ContractResolver might run into threading issues. If I change it for one request is it going to be valid for all requests thereafter until someone changes it on another request (seems so through testing) If that is the case, then I don't see the usefulness for my purpose.
In summary, I am looking for a way to have dynamic data models such that the output from a request is configurable by the client on a request by request basis. Google implements this in their web api and they call it "partial response" and it works great. My implementation works, to a point but I fear that it will be broken for multiple simultaneous requests.
Suggestions? Tips?
A simpler solution that may work.
Create a model class with all 50 members with nullable types.
Assign values to the requested members.
Just return the result in the normal way.
In your WebApiConfig.Register() you must set the null value handling.
config.Formatters.JsonFormatter.SerializerSettings =
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
You must not touch the configuration. You need the contract resolver on per-request basis. You can use it in your action method like this.
public class MyController : ApiController
{
public HttpResponseMessage Get()
{
var formatter = new JsonMediaTypeFormatter();
formatter.SerializerSettings.ContractResolver =
new DynamicContractResolver(new List<string>()
{"Id", "LastName"}); // you will get this from your filter
var dto = new MyDto()
{ FirstName = "Captain", LastName = "Cool", Id = 8 };
return new HttpResponseMessage()
{
Content = new ObjectContent<MyDto>(dto, formatter)
};
// What goes out is {"LastName":"Cool","Id":8}
}
}
By doing this, you are locking yourself into JSON content type for response messages but you have already made that decision by using a Json.NET specific feature. Also, note you are creating a new JsonMediaTypeFormatter. So, anything you configure to the one in the configuration such as media type mapping is not going to be available with this approach though.
I know this question is from many years ago, but if you're looking to do this with modern releases of the framework, I'd recommend nowadays to use OData services (http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/using-select-expand-and-value).
I am trying to create a REST service using Nancy FX in a C# environment. I can easily do a Response.AsJson and it all looks good. But I want the response to omit any properties that are null.
I have not been able to figure out how to do this yet.
Could someone point to me towards a help document or a blog post somewhere, that explains how to do this.
Thanks,
JP
I would create a dynamic anonymous type and return that. So let's say you have a User object like this:
public class User
{
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
You want to pass back an instance of this type as a JSON response so you will have some code like this:
Get["/user/{userid}"] = parameters =>
{
var user = UserService.GetById(Db, (string)parameters.userid);
if (user == null) return HttpStatusCode.UnprocessableEntity;
return Response.AsJson(user);
};
But you don't want to return the User instance, instead you want to return an separate instance of a dynamic type that will only implement a property if the property value is not null for a given instance.
So I would suggest code something like this:
Get["/user/{userid}"] = parameters =>
{
var user = UserService.GetById(Db, (string)parameters.userid);
if (user == null) return HttpStatusCode.UnprocessableEntity;
dynamic userDTO = new ExpandoObject();
userDTO.Id = user.Id;
if (!string.IsNullOrEmpty(user.FirstName)) userDTO.FirstName = user.FirstName;
if (!string.IsNullOrEmpty(user.LastName)) userDTO.Lastname = user.LastName;
return Response.AsJson((ExpandoObject)userDTO);
};
Note 1
You don't need to test for the Id since that is implied by the successful return of the User instance from the database.
Note 2
You need to use a dynamic type so you can include ad hoc properties. The problem is that extension methods cannot accept dynamic types. To avoid this you need to declare it as an ExpandoObject but use it as a dynamic. This trick incurs a processing overhead but it allows you to cast the dynamic to an ExpandoObject when passing it in to the AsJson() extension method.
I am using a online tutorial to lean how to create a web service, generate a JSON object, send it back to my Win 8 App and display it. The web service is working however I am struggling to return a value to the APP. My code in the app is:
WinJS.xhr({
url: 'http://localhost/filmgloss/web-service.php?termID=1&format=JSON'
})
.done(
function complete(result) {
// terms is the key of the object
for (var terms in result) {
for (var term in terms) {
if (result.hasOwnProperty(term)) {
//here you have to acess to
var termName = result[term].termName;
var def = result[term].definition;
}
//Show Terms
testDef.innerText = definition;
}
}
},
And he code in my web service is:
if($format == 'json') {
header('Content-type: application/json');
echo json_encode(array('terms'=>$terms));
}else...
The JSON output itself looks like:
{"terms":[{"term":{ "termName":"Focus","definition":"A Focus..."}}]}
I am using a for..in but whilst I can look inside terms' I can't work out how to look interm`
I usually build my own data structure that represents the JSON structure.
In your case it would be something like this:
public class TermsList
{
public List<Term> terms { get; set; }
}
public class Term
{
public string termName { get; set }
public definition termName { get; set }
...
}
Then you can just deserialize your string into your object. There are different ways to do this. I would use Json.Net.
Here is one way:
Parse JSON in C#
public static T Deserialise<T>(string json)
{
T obj = Activator.CreateInstance<T>();
using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
obj = (T)serializer.ReadObject(ms); // <== Your missing line
return obj;
}
}
If you wanna keep it dynamic, that should work too:
http://www.drowningintechnicaldebt.com/ShawnWeisfeld/archive/2010/08/22/using-c-4.0-and-dynamic-to-parse-json.aspx
I have managed to resolve my issue with the help of a developer friend. My problem was that I had not realised that the result of WinHS.xhr was not already a JSON Array. Although my web-service outputs a JSON Array when it is consumed through WinHS.xhr it appears to be returned as an XMLHttpRequest object.
The solution was therefore to process the result using:
JSON.parse(result.responseText)
I could then use a For...In loop as expected:
for (terms in responseTerms) {
//terms will find key "terms"
var termName = responseTerms.terms[0].term.termName;
var termdefinition = responseTerms.terms[0].term.definition;
testTerm.innerText = termName;
testDef.innerText = termdefinition;
}
Thanks for everyone that commented, hopefully this may help others in the future if they're starting out with Win 8 app development.
I am looking for sending JSON object to the server via GET.
Chris's answer on Post an Array of Objects via JSON to ASP.Net MVC3 works for the http POST but not for GET.
My case also works for POST but not for GET. What can I do to make GET work
Here is my case:
in Controller I have the following method
public ActionResult Screenreport(Screentable screendata)
{
// do something here
return View();
}
I have two ModelView as follows:
public class Screenrecord
{
public string Firstname{ get; set; }
public string Lastname{ get; set; }
}
public class Screentable
{
public List<Screenrecord> Screenlist { get; set; }
}
On the client side I generate JSON object
var Screentable = { Screenlist: screendata };
screendata is an array of Screenrecord
All this work when I use POST but when I use GET I am getting null value (screendata = null) Controllers' method.
In other word when click GO, screendata is null in Screenreport(Screentable screendata) routine.
Also, if I send one JSON object it works but if I send an array (list) like I described, it does not.
Is what I am trying to do doable?
No :-)
Thats not how get works.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
(see 9.3 GET)
"The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI"
Request-URI being the important part here. There is no concept of body data in a GET request.
Try changing method to public ActionResult Screenreport(HttpRequestMessage request)
Then use below code to get JSON object.
data = request.RequestUri.Query;
data = HttpUtility.ParseQueryString(data).Get("request");
Try this example in Javascript:
var someObject = {
id:123456,
message:"my message",
}
var objStr = JSON.stringify(someObject);
var escapedObjStr = encodeURIComponent(objStr);
var getUrlStr = "http://myserver:port?json="+escapedObjStr
and now you can forward this URL to your server. I know this is not in any .NET language but you can definitely find the equivalent methods used, or just use the JS right away.
public class JsonCategoriesDisplay
{
public JsonCategoriesDisplay() { }
public int CategoryID { set; get; }
public string CategoryTitle { set; get; }
}
public class ArticleCategoryRepository
{
private DB db = new DB();
public IQueryable<JsonCategoriesDisplay> JsonFindAllCategories()
{
var result = from c in db.ArticleCategories
select new JsonCategoriesDisplay
{
CategoryID = c.CategoryID,
CategoryTitle = c.Title
};
return result;
}
....
}
public class ArticleController : Controller
{
ArticleRepository articleRepository = new ArticleRepository();
ArticleCategoryRepository articleCategoryRepository = new ArticleCategoryRepository();
public string Categories()
{
var jsonCats = articleCategoryRepository.JsonFindAllCategories().ToList();
//return Json(jsonCats, JsonRequestBehavior.AllowGet);
return new JavaScriptSerializer().Serialize(new { jsonCats});
}
}
This results with following:
{"jsonCats":[{"CategoryID":2,"CategoryTitle":"Politika"},{"CategoryID":3,"CategoryTitle":"Informatika"},{"CategoryID":4,"CategoryTitle":"Nova
kategorija"},{"CategoryID":5,"CategoryTitle":"Testna
kategorija"}]}
If I use line that is commented and place JsonResult instead of returning string, I get following result:<
[{"CategoryID":2,"CategoryTitle":"Politika"},{"CategoryID":3,"CategoryTitle":"Informatika"},{"CategoryID":4,"CategoryTitle":"Nova
kategorija"},{"CategoryID":5,"CategoryTitle":"Testna
kategorija"}]
But, I need result to be formatted like this:
{'2':'Politika','3':'Informatika','4':'Nova
kateorija','5':'Testna kategorija'}
Is there a simple way to accomplish this or I will need to hardcode result?
Have a look at the Json.Net library
The Json.NET library makes working
with JavaScript and JSON formatted
data in .NET simple. Quickly read and
write JSON using the JsonReader and
JsonWriter or serialize your .NET
objects with a single method call
using the JsonSerializer.
I have successfully used it within a .net mvc project.
ile,
you really should look at the json.net lib, i was in a similar dilemma recently with json/jquery and mvc and tried my own hand-rolled version but hit the many limitations in my own implemetation. the newton json lib is quite simply a no-brainer - simple to use and always being updated. the current version works fantastically with nested structures, thus making that particular json formatting issue a non-issue.
give it a look, will take you 15 mins to get to grips with.
Try returning it as an Array, Also if you return a JsonResult you can save alot of code (looks like you were attempting to get the formatting you wanted)
public class ArticleController : Controller
{
ArticleRepository articleRepository = new ArticleRepository();
ArticleCategoryRepository articleCategoryRepository = new ArticleCategoryRepository();
public JsonResult Categories()
{
var jsonCats = articleCategoryRepository.JsonFindAllCategories().ToArray();
return Json(jsonCats, JsonRequestBehavior.AllowGet);
}
}
in my test I got a result of
[{"Id":1,"Name":"Cat 1"},{"Id":2,"Name":"Cat 2"}]