Saturday, December 10, 2016

Sitecore Item browser and technical doco viewer tool

Jumpstart

This module is available in Sitecore Market place and source code in git.

This tools saves time in creating and extracting sitecore item defination. This browser and viewer can be used for review, quick lookup and extract for technical documentation.
Support Prerequisites
  • Tested in Sitecore Xp
  • Worked well with sitecore mvc renderings. Not tested for components with sublayout

Work in progress
  • Root element such home is not displayed and view. Will be available in next release.
  • Must be installed only in development environment in CMS content authoring server or local 
  • Not suitable for CD or production or test env.

This module is about browsing and viewing sitecore item technical definition such as template, layout, device, presentation and fields definition for given sitecore item in content tree. This is very useful tool to extract content for technical document for any project. It gives all details of given item its template, base template, renderings, datasource and all. So all we need to do is to browse and extra the definition for our technical documentation. 
Once this package is installed ,you can browse item defination and details using below url.

  • http://website/sitecore/admin/browsedoco.aspx 
  • http://website/sitecore/admin/knowMe.aspx 

you can also find the source code available in  
https://github.com/poojarsn/MyDoco





Saturday, November 26, 2016

LINQ Performance pitfall instead a Pit stop!

I would rather named the title as Linq performance pit stop. Anyway in the interest of time, here is, one of the good examples of how we can start with something very trivial linq query to something convoluted one. Always remember the query in memory or on fly comes with its own pros and cons. One must understand how to use them and when. I took this particular example from pluralsight and thought it to be worth sharing.

Courtesy
https://app.pluralsight.com/library/courses/linq-more-effective/table-of-contents

by Mark Heath.

Slow
var longest=books.First(b => b.Pages==books.Max(a => a.Pages));

Better
var mostBooks= books.Max(a => a.Pages);
var longest=books.First(b => b.Pages == mostBooks);

Best
var longest= books.MaxBy(p => p.Pages);

Hope this useful.

SingleOrDefault() 
Check before using FirstOrDefault
This should be used if query returns single recordset.

var scalarDataSet= result?.Results?.SingleOrDefault();


Linq Data Parallelism
var quotes = quotesForAllProducts();//e.g Get quotes for all products
Parallel.ForEach(products, item => Process(item,quotes));
private void Process(Product item,List<Quote> quotes)       {           var quote= quotes?.SingleOrDefault                   (p =>                       p.Id.Trim().Equals(item.Id ?? string.Empty));           if (quote != null)           {               item.Cost = quote.TotalAmount.GetValueOrDefault();               item.Code = quote.Code;           }                  }

Parrallelism
System.Linq.ParallelEnumerable
Set object values for superset.
Packages = poducts.AsParallel().Select(p => new Package                 {                     tId = p.tId,                     vId = p.vId                 }).ToList(),

SelectMany
private void SetProductsSubSet(IList<Product> products)     {         _products= (IEnumerable<ProductDetail>) products?.AsParallel().SelectMany(a => a.subLevel.Select(p => new ProductDetail         {             Id = a.Id,             Type = a.Type,         })) ?? new List<ProductDetail>();       } 


DefaultIfEmpty() Left Join
public List<Product> AddHospitalAndExtrasProduct()        {            return                 (from A in Main                join B in SubB on A.ID equals B?.Id into MainAndSubB                    from ResultSetA in MainAndSubB.DefaultIfEmpty()                join B in SubC on A.ID equals C?.Id into MainAndSubC                    from ResultSetC in MainAndSubC.DefaultIfEmpty()
            select new Product             {                 Id = Main.Id,                 Name = Main.Name,                 SubBId = ResultSetA != null ? ResultSetA .SubBId : string.Empty,                 SubCId = ResultSetC != null ? ResultSetC .SubCId : string.Empty,             }).ToList();                   }


Wednesday, September 28, 2016

Check field Template Source value using sitecore powershell SPE

Use Case :Review

Suppose we have a custom rich text  and it has been sourced with custom component or css .This is added when developer creates template field in data template. The below code snippet can be used as part of your review and refactoring process to clean up sitecore items. 

Here is the quick pick..Check Source field of rich text is empy or null.

$targetTemplate    = Get-item 'master:/sitecore/templates/User Defined/Common/Data';
$templateFilter    = Get-Item "master:/sitecore/templates/System/Templates/Template Field";


Get-ChildItem $targetTemplate.FullPath -recurse 
| Where-Object { $_.TemplateName -eq $templateFilter.Name -and $_.type -eq 'Rich Text' -and $_["source"] -eq ''} 
| ForEach-Object {
    $_.Name
    $_.Type
    $_["Source"] 
}

Reference


http://sitecore.stackexchange.com/questions/203/unable-to-get-value-of-source-using-spe

Add base template using sitecore powershell extension

Use Case

It might happen you may have to add base template to all your user defined template. Below is the script to help doing this. I used Adam's code as reference to get this working. During development we could have reach to a stage where we end up with lot of user defined templates and at some point we review and refactor template to have uniform approach. One of the script below can come handy to save some of our refactoring time.

# Add base template programmatically


$targetTemplate    = Get-item 'master:/sitecore/templates/User Defined/Common/Data';
$templateFilter    = Get-Item "master:/sitecore/templates/System/Templates/Template";
$templateToBeAddAsBaseTemplate     = Get-Item 'master:/sitecore/templates/User Defined/Common/Data/Carousel'


Get-ChildItem $targetTemplate.FullPath -recurse | Where-Object { $_.TemplateName -eq $templateFilter.Name -and $_.Name -eq "promo"} | ForEach-Object {
    if(-not ($_."__Base template" -match "$($templateToBeAddAsBaseTemplate.Id)")){
           #If not exist then add
         $_."__Base template" = "$( $_."__Base template")|$($templateToBeAddAsBaseTemplate.Id)" 
    }
}

Reference

http://stackoverflow.com/questions/18990973/append-base-template-to-template-using-sitecore-powershell

Add base template using sitecore powershell extension

Use Case

It might happen you may have to add base template to all your user defined template. Below is the script to help doing this. I used Adam's code as reference to get this working. During development we could have reach to a stage where we end up with lot of user defined templates and at some point we review and refactor template to have uniform approach. One of the script below can come handy to save some of our refactoring time.



$targetTemplate    = Get-item 'master:/sitecore/templates/User Defined/Common/Data';
$templateFilter    = Get-Item "master:/sitecore/templates/System/Templates/Template";
$templateToBeAddAsBaseTemplate     = Get-Item 'master:/sitecore/templates/User Defined/Common/Data/Carousel'


Get-ChildItem $targetTemplate.FullPath -recurse | Where-Object { $_.TemplateName -eq $templateFilter.Name -and $_.Name -eq "promo"} | ForEach-Object {
    if(-not ($_."__Base template" -match "$($templateToBeAddAsBaseTemplate.Id)")){
           #If not exist then add
         $_."__Base template" = "$( $_."__Base template")|$($templateToBeAddAsBaseTemplate.Id)" 
    }
}

Reference

http://stackoverflow.com/questions/18990973/append-base-template-to-template-using-sitecore-powershell

Monday, September 12, 2016

Sitecore CMS Active Directory Module and LDAP integration.

Introduction

I'm not going to reinvent the wheel. The idea is to help fellow developer to troubleshoot and few show stoppers that can come as a problem during integration of ldap to sitecore AD Module. I just try to put my experience altogether so as to address some issues and useful tool that can help you get started.

Use Cases

Enabling LDAP authentication in content authoring aka CMS system will provide additional level of security access control in place. This will ensure limited access and no misuse even we have CMS -CA accessible only to internal network non accessible publicly.

Assumption:

You've LDAP /AD account in place. Say. There is dev, test and prod group account created in AD. To each of these group set of AD users are assigned. Each of these group must be assigned with Service account say sv_dev_user.and so on. The Service account act as primary source of authentication to allow any external system seek access to AD group. Later it will enable set of users to access application or system.

  • Development/Test/Production Environment
    • AD GROUP 
      • AD User(s) 
      • One Service Account
Note : The service account is one that is used by sitecore AD Module.

This is used by one of the sitecore configuration.
add name="customAD" type="LightLDAP.SitecoreADMembershipProvider" connectionStringName="LDAPConnString" applicationName="sitecore" minRequiredPasswordLength="1" minRequiredNonalphanumericCharacters="0" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
connectionUsername="[Enter SERVICE Account User Name]" connectionPassword="[Enter Password]" connectionProtection="Secure" attributeMapUsername="sAMAccountName" enableSearchMethods="true"

***Facts About:AD Service Account Vs AD User Account

In certain scenarios we have systems running under AD Credentials (i.e. under a Service Account). These Service Accounts are created in exactly the same way as user accounts; the only difference being the name and description. A few things have been done to make a distinction between the two account types (e.g. which OU the account is in, whether "password never expires" is enabled, if "service account" is in the description), but there's no one rule which can be applied to everything to clearly distinguish between the two.

How to get Started?

Follow this blog , this more precise and easy steps to start with.

Troubleshooting?  

1. OU Group wrongly used in LDAP Connection string?

Always look at the right form of LDAP connection string. 99% of the cases Ldap connection is wrongly used in terms of OU group. There may be nested OU group. The best way to figure out OU group is use LDAPAdmin.exe. Check download section.

Connect LdapAdmin with service account userId and pwd. Once connected to LDAPAdmin try to locate AD Group and take one member(user) of that group and check its property . You can easily find the right hierarchy of OU aswell as right OU group.

2. Check LDAP Port in Ldap connection string?

  • Port 389(used for ldap browsing) vs 636 (secure)
add name="LDAPConnString" connectionString="LDAP://Mydomain:389/OU=SomePrimaryOU,OU=SomeChildOU,DC=Mydomain,DC=myCompany,DC=com,DC=au"

3. Always verify connectivity of LDAP AD account from server

One way to check directly using ldapAdmin.exe or you can check through this simple code base.

using System.DirectoryServices;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //mycompany.com.au
            var entry = new DirectoryEntry(@"LDAP://yourdomain:636/OU=primary,OU=secondary,DC=yourdomain,DC=mycompany,DC=com,DC=au", "Active directory user name","password");

            var search = new DirectorySearcher(entry);
            SearchResult result = search.FindOne();  

      }
      }
}

4. Sitecore Provider Status

                                       http://mydemo/sitecore/admin/providerstatus.aspx


5. User Manager : AD User Import Status Successful!


6. Domain: Check CustomAD Domain appeared!


7. Role Manager: Assign Sitecore Role to User

Make sure Sitecore Client Role is assigned to AD users.


8. Finally Login with AD user account

Ensure you using the domain name that you added as one of the membership provider. say you got domain name mydomain and you have used membership provider as below. Then you should login with customAD\UserId

add name="customAD" type="LightLDAP.SitecoreADMembershipProvider" connectionStringName="LDAPConnString" applicationName="sitecore" 

Last but not the least

If you unable to get any lead. Enable debug mode to true in ldap.config

Open the /App_Config/Include/ldap.config file, locate the LDAP.Debug setting and set it to true.
This setting is set to false by default. When the changes to the pluggable .config file are applied immediately, the next request to the module will dump much more information to the Sitecore CMS log file.

Downloads

References

Azure Cloud

Friday, August 26, 2016

Sitecore MVC Session handling

It all started when we had session timeout and it resulted in error page. Yes session checks were not handled properly.All I was looking to solve this trivial problem with quick code fix but it turn out to be a bit of research again. This is indeed a sitecore world, where every request surface with filters, route and action. Each request is fragmented as we had controller rendering to serve all our dynamic data and transaction commits.

****Register Global Filter to check for session. 
This will not work as there are some workflow pages which are not session or authorization dependent. It bit the purpose.

Next thought of handling this in SessionEnd pipeline.
GlobalFilters.Filters.Add(new SessionExpireAttribute());

****SessionEnd Pipeline Response.Redirect and Server.Transfer will not work!

Session_End is fired internally by the server, based on an internal timer. And thus there is no HttpRequest associted when that happens. That is why Response.Redirect or Server.Transfer does not make sense and will not work. 

**** SessionEnd is not fired if session mode is outproc.
It will be fired only when using session mode set as inproc or Custom.

****Solution: Not elegant but it worked.
Let the session timeout and then eventually it will be send to the path of common error handling module where we can take appropriate action to redirect it to login page or some information page to notify user about session timeout.
 
****Post Session Timeout-  User action server side event.
****Post Session Timeout- User action cliend side event fired.(Check for IsAjaxRequest)
 public class RenderingControllerExceptionProcessor : ExceptionProcessor
{  
    public override void Process(ExceptionArgs args)
    {
            var userContext = SessionService.Get();
            if (userContext == null)
                if (args.ExceptionContext.HttpContext.Request.IsAjaxRequest())
                {
             //send something to response result.
                    args.ExceptionContext.Result = new JsonResult
                    {
                        Data = new
                        {
                            Error = "NotAuthorized",
                            LogOnUrl = "/login"
                        },
                        JsonRequestBehavior = JsonRequestBehavior.AllowGet
                    };
                }
                else
                {
                    WebUtil.RedirectToLoginPage();
                }
   }
}
OR
 private bool IsSessionExpired()
        {
            if (HttpContext.Current.Session != null)
            {
                
                if ( HttpContext.Current.Session.IsNewSession)
                {
                    //Note: Below code fails for Custom session.Works for Inproc
                    string cookieHeaders = HttpContext.Current.Request.Headers["Cookie"];

                    if ((null != cookieHeaders) &&
                       (cookieHeaders.IndexOf("ASP.NET_SessionId", StringComparison.Ordinal) >= 0))
                    
                        // IsNewSession is true, but session cookie exists,
                        // so, ASP.NET session is expired
                        return true;
                    
                }
                // Session is not expired and function will return false,
                // could be new session, or existing active session
                return false;
            }
            return false;
        }
The only solution is to handle through global application error event in sitecore rendering.


Always Consider these values when dealing with session:.

  1. Polling interval
  2. Compression
  3. Session type
  4. SlidingExpiration

Side Note:
If your worker process restarts and it causes your cache to clear, think of using agent to ping Keepalive.aspx.

Monday, August 22, 2016

How string Interpolation can simplify expression? No more string.format

Just this example 


Console.WriteLine($"When {condition} is true, {(condition ? "it's true!" : "It's False")}");

C# Simplify Dispose Object

public void RetireHenchman()
{
    var disposableMinion = Minion as IDisposable;
    if (disposableMinion != null)
        disposableMinion.Dispose();
    Minion = null;
}
 
The null coalescing operator can make this code more concise as well:
 
public void RetireHenchman()
{
    (Minion as IDisposable)?.Dispose();
    Minion = null;
}
 


Friday, August 19, 2016

MVC Filter Order

While dealing with MVC filters we got various options to tweak the flow of action method calls at local and global level of application execution, The best case scenario are as follows:-

1. Check authorization for each action call.
2. Check whether request is legitimate as if it is human or bot based
3. Check or validate model request
4. Check session timeout
5. Check request length

[Authorize]--AuthorizeAttribute


  • IsAuthorized
  • OnAuthorized

public class ProtectedApiAttribute : AuthorizeAttribute
    {
        public ProtectedApiAttribute()
        {
            // do nothing, _repository will be lazily instantiated
        }
 
 
        protected override bool IsAuthorized(HttpActionContext actionContext)
        {
            var methodAccess = string.Empty;
            if (actionContext.Request.Method == HttpMethod.Get) methodAccess = "Get";
            if (actionContext.Request.Method == HttpMethod.Post) methodAccess = "Post";
            if (actionContext.Request.Method == HttpMethod.Put) methodAccess = "Put";
            if (actionContext.Request.Method == HttpMethod.Delete) methodAccess = "Delete";
 
            var isAuthorised = false;
            if (HttpContext.Current.Session.Count > 0)
            {
                isAuthorised = true;
            }
            return isAuthorised;
        }
    }
}


Filters run in the following order:
  1. Authorization filters
  2. Action filters
  3. Response filters
  4. Exception filters
For example, authorization filters run first and exception filters run last. Within each filter type, the Order value specifies the run order. Within each filter type and order, the Scope enumeration value specifies the order for filters. This enumeration defines the following filter scope values (in the order in which they run):
  1. First
  2. Global
  3. Controller
  4. Action
  5. Last

Thursday, August 18, 2016

C# 6.0 Initialization Gotchas

class Program
    {
        static void Main(string[] args)
        {
           var container = new SomeContainer();
           var range = Enumerable.Range(0, 10);
           foreach (var item in range)
               container.SomeNumbersHasSolution.Add(item);
 
           Console.WriteLine(container.SomeNumbersHasSolution.Count);
 
           foreach (var item in range)
               container.SomeNumbersHasProblem.Add(item);
 
           Console.WriteLine(container.SomeNumbersHasProblem.Count);
 
           Console.Read();
       }
       public class SomeContainer
       {
           public IList SomeNumbersHasProblem => new List();
           public IList SomeNumbersHasSolution { get; } = new List();
 
       }



  • SomeNumberHasProblem---Result 0
  • SomeNumberHasSolution---Result 10

Wednesday, August 17, 2016

Hail, Architect- Don't just get swayed by the hype around new releases of Sitecore.

It's not just about sitecore or it's new releases or update which is announced to all out there. Its about plan it and time it well. Your stakeholder is dependent upon you. What you say is written on the stone. So be careful. Like all other releases of software or product there is cooling period for any product to get matured and get adopted to the ecosystem. What I meant is a time to make your product stand strong against all issues which may surface in production and can haunt you for a week. If you see in the past almost all product or software underwent changes due to fixes or unstable or may be success to certain degree or call it a flop show.

Having said this, cooling period is something one must consider while setting up expectation with stakeholder. Watch the space carefully. 

Just don't get swayed by the hype of features it comes with rather you face the reality with risk/issues the new release can offer in return.

Next time you hear something about releases with new feature .Hold your horses! 

Assess it well! Act Smart ! Sell while Deliver !


This is my opinion and may not concur with everyone.



Tuesday, August 16, 2016

How to get to the bottom of Sitecore Performance issues?

The idea is to give the quicklinks to gather data for performance issue analysis. Most of us may not be aware about the intrinsic .net framework and internal of CLR in details as we more focus on implementations and make use of features. This is where actual concept comes into play.


Debugging TOOL

1. DebugDiag

https://channel9.msdn.com/Shows/Defrag-Tools/Defrag-Tools-122-DebugDiag-Part-2
Performance counters
Proc Dump

2. Debugging Production Environment Windbg & SOS

https://channel9.msdn.com/Series/-NET-Debugging-Stater-Kit-for-the-Production-Environment/Windbg--SOS-03

3. Sons of Strike- SOS.dll

https://msdn.microsoft.com/en-us/library/bb190764(v=vs.110).aspx

If you really want to deep dive further refer Tezz Fernandez blogs and articles.

A long story short, if you are into critical production performance issue, sitecore support team may need your help to get certain process stats and data here are the few links that you must go through to nail down the issues.
https://blogs.msdn.microsoft.com/tess/

Some unanswered Questions?

Q.1  How to collect memory dumps using Task Manager ?
https://kb.sitecore.net/articles/758511

Q.2. How to collect memory dumps using ProcDump ?
https://kb.sitecore.net/articles/253710

Q.3. How to identify Sitecore process in Performance Monitor ?
https://kb.sitecore.net/articles/931689

Q.3. How to collect memory dumps using Managed GC Aware Dump ?
https://kb.sitecore.net/articles/284285

Q.4. How to collect memory dumps ?
https://kb.sitecore.net/articles/488758

Deep Containment Designs

var location = default(string);
if (vendor != null)
{
    if (vendor.ContactPerson != null)
    {
        if (vendor.ContactPerson.HomeAddress != null)
        {
            location = vendor.ContactPerson.HomeAddress.LineOne;
        }
    }
}

Now, using C# 6, this same idiom becomes much more readable:

var location = vendor?.ContactPerson?.HomeAddress?.LineOne;







Tuesday, August 9, 2016

Sitecore Database Internal -Items, VersionedFields and UnVersionedFields

These tables pretty much make sitecore CMS. Items and values stored in fields. Everything is just an ITEM.


SELECT [Id]
      ,[ItemId]
      ,[Language]
      ,[FieldId]
      ,[Value]
      ,[Created]
      ,[Updated]
      ,[DAC_Index]
  FROM [Sitecore_master].[dbo].[UnversionedFields]

SELECT [Id]
      ,[ItemId]
      ,[Language]
      ,[Version]
      ,[FieldId]
      ,[Value]
      ,[Created]
      ,[Updated]
      ,[DAC_Index]
  FROM [Sitecore_master].[dbo].[VersionedFields]

SELECT [ID]
      ,[Name]
      ,[TemplateID]
      ,[MasterID]
      ,[ParentID]
      ,[Created]
      ,[Updated]
      ,[DAC_Index]
  FROM [Sitecore_master].[dbo].[Items]

Monday, August 8, 2016

Capture Asp.net webservice traffic request when using with sitecore

I was doing bit of research playing around postman interceptor and fiddler but couldn't find the solution to view the calls made by sitecore.net to asp.net webservice that is been called as part of middle tier.

Even Redgate Ant profiler even could not able to capture such outgoing requests to other asp.net webservice. The idea was to assess the response time elapsed to get data from external webservice to our sitecore solution. We want to make sure what we developed in sitecore will be as optimum in terms of our design approach. We ensured most of the component is cached and rendered appropriately.

  • Doing this you can see performance profiling stats of outgoing request to external api , web service, wcf service etc.
  • You can see them available in Redgate Ants performance profiler and VS2015 n tier profiling.
  • Fiddler to give you all in and out of http requests.
 
Finally i was surfing through knowledge base of sitecore and happen to find this work around.
Note: The profiler will only capture requests made by System.Net.HttpWebRequest

Courtesy Sitecore
https://kb.sitecore.net/articles/017181



Solution






To configure the Fiddler tool to capture web service calls from an ASP.NET web site, you need to perform the following actions on your solution:
  1. In the Global.asax file, implement the following Application_Start method:
        public void Application_Start()
        {
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
        }
    
  2. In the Global.asax file, add the following import statements:
    <%@ Import Namespace="System.Net" %>
    <%@ Import Namespace="System.Net.Security" %>
  3. In the web.config file, configure the following XML under the section:
    <system .net>
      <defaultproxy enabled="true" usedefaultcredentials="true">
        <proxy autodetect="false" bypassonlocal="false" proxyaddress="http://127.0.0.1:8888" usesystemdefault="false">
      </proxy>

</configuration>


  • Enable Fiddler to capture the HTTPS traffic.

  • After the traffic is captured by Fiddler, it can be saved for further sharing and analysis.

    Saturday, July 23, 2016

    Sitecore Media Library like never before. Mind it before you leave its configuration unattended

    According to me this topic is mostly overlooked and realized when it is in post production environment. It isn't that the sitecore media library is simple to use perhaps it is the only area where the subject is realized when dealt with different scenario.

    Here is some of the scenarios I remember at top of my head.
    • Media is cached at client or end user browser
    • Media cached at server side
    • Media is uploaded in file system and database without proper instruction set to the end-users. Then comes the problem such as multi content delivery sync with one authoring server. Architecture decision. 
    • For multi-server environments, media must be propagated from the CMS server to the
    • content delivery server(s) using the Sitecore Staging module
    • AA Compliance site where image alt text is mandatory and content author dependency on alt text.etc.
    • Performance and security concerns around media library.
    • Performance hit if stored files in database as compared to disk. 

    Here is few important settings that are important to take before it is released to production.
    Locate these configuration in sitecore.config

    MEDIA - DISABLE FILE MEDIA
      <!--  MEDIA - DISABLE FILE MEDIA
                Enables or disables storage of media as files rather than database records.
                If true, user interfaces do not present options to store media as files.
                All files will be stored in the database, disregarding the value of the Media.UploadAsFiles setting.  
               
                Default value: false
          -->

        <setting name="Media.DisableFileMedia" value="false">

    MEDIA - CACHING ENABLED -Content delivery at SERVER Side

      <!--  MEDIA - CACHING ENABLED
                Indicates if caching of media files is enabled.
                Default value: true
          -->
        <setting name="Media.CachingEnabled" value="true" />

    MEDIA - MAX SIZE IN MEMORY to edit media content

       <!--  MEDIA - MAX SIZE IN MEMORY
                The maximum size of media to load into memory for processing (resizing etc.).
                Default value: 40MB
          -->

    MEDIA - MAX SIZE IN DATABASE to transfer and commit media in database

     <!--  MEDIA - MAX SIZE IN DATABASE
                The maximum allowed size of media intended to be stored in a database (binary blob).
                This value must be less than the ASP.NET httpRuntime.maxRequestLength setting.
                Default value: 500MB
          -->
        <setting name="Media.MaxSizeInDatabase" value="500MB" />

    MEDIA - AUTO SET ALT

     <!--  MEDIA - AUTO SET ALT
                Indicates if the Alt field on the Image template is set automatically to the file
                path when the image is uploaded. If false, the Alt field is blank.
          -->
         <setting name="Media.AutoSetAlt" value="false" />

    MEDIA BROWSER CACHED 

    ***The most important ones. Look into this configuration carefully. Read through.
    I'll give you the real time scenario. Just imagine website is developed and released to production. Everything is going fine and this website is big brand corporate facing website which is publicly available. Unfortunately there is media release that needs urgent update to important policy document without changing the media url as this media url is used everywhere in newsletter and corporate bible and so on. Now there is content author or business marketing team that wants to change the file content and upload with same file name immediately. 
    BOOM! .......................
    Despite all the efforts with proper publish and all the changes done correctly still the new file with same name and url is not reflecting in the content delivery website. The reason is... it is cached in client and server browser. Production support team is called for the rescue with P2 level raised as service incident request. 

    https://kb.sitecore.net/articles/218124

    Courtesy Sitecore.
    When new content is attached to an already published media item and the media item is published again, the content change might not be reflected in the browser immediately when you access the media using its URL.
    This happens because the media is cached in the browser for the time specified in the MediaResponse.MaxAge setting. If a browser has already accessed the media item, it may not perform any requests to the server and may retrieve the media item from its cache until the cached version expires.

     <!--  MEDIA RESPONSE - CACHEABILITY
                The cacheability to use in media response headers.
                Possible values: NoCache, Private, Public, Server, ServerAndNoCache, ServerAndPrivate
                Default value: private
          -->
         <setting name="MediaResponse.Cacheability" value="private" />
        !--  MEDIA RESPONSE - CacheExtensions
                The cache extension(s) to use in media response headers.
                Default value: ""
          -->
         <setting name="MediaResponse.CacheExtensions" value="" />
        <!--  MEDIA RESPONSE - MAX AGE
                The max age to use in media response headers.
                Set it to "00:00:00" to omit this header.
                Default value: 7.00:00:00 (seven days)
          -->
         <setting name="MediaResponse.MaxAge" value="7.00:00:00" />
         <!--  MEDIA RESPONSE - SLIDING EXPIRATION
                The sliding expiration to use in media response headers.
                Set it to "" to omit this header. To include it, use "true" or "false".
                Default value: ""
          -->
         <setting name="MediaResponse.SlidingExpiration" value="" />


    Reference:

    https://sdn.sitecore.net/upload/sdn5/articles%202/media/media%20facilities/sitecore%20media%20facilities.pdf



    https://doc.sitecore.net/sitecore_experience_platform/content_authoring/media_items/using_media_items/upload_a_file_to_the_media_library